记录自己想到的和遇到的收集一些高级 TS 类型的代码
数组不为空
一道面试题,如何定义一个不是空数组的数组?
// 怎么定义类型,约束数组中值至少有一项
const a: number[] = []
点击查看答案
// 解法一
type NotAmptyArray<T> = [T, ...T[]]
// 解法二
type NotAmptyArray<T> = T[] & { 0: T }
全部可选的参数对象至少包含一个 key
自己想出来的一个问题,语言不好描述,看下面代码
interface A {
a?: number
b?: boolean
}
declare function main(opt: A): void
// 怎么定义一个类型,使得参数对象中至少包含一个 key?
main({})
点击查看答案
interface A {
a: number
b: boolean
}
type AtLeastOne<T> = {
[K in keyof T]: Pick<T, K> & Partial<Omit<T, P>>
}[keyof T]
declare function main(opt: AtLeastOne<A>): void
main({ a: 1 })
给定的类型可选
在下面的实例中,实现 SetOptional,可使得给定的 key 为可选
type Foo = {
a: number;
b?: string;
c: boolean;
}
// 实现 SetOptional
type SomeOptional = SetOptional<Foo, 'a' | 'b'>;
// type SomeOptional = {
// a?: number; // 该属性已变成可选的
// b?: string; // 保持不变
// c: boolean;
// }
点击查看答案
// 解法一
type SetOptional<T, N extends keyof T> = {
[P in keyof T]: Partial<Pick<T, N>> & Pick<T, Exclude<keyof T, N>>
}[keyof T]
// 解法二
type Simplify<T> = {
[P in keyof T]: T[P]
}
type SetOptional<T, K extends keyof T> =
Simplify<Partial<Pick<T, K>> & Pick<T, Exclude<keyof T, K>>>
条件 Pick
根据值类型进行筛选
interface Example {
a: string;
b: string | number;
c: () => void;
d: {};
}
// 测试用例:
type StringKeysOnly = ConditionalPick<Example, string>;
//=> {a: string}
点击查看答案
// 首先将类型对应的 key 找出来,然后再进行 Pick
type ConditionalKeys<T, Condition> = {
[P in keyof T]: T[P] extends Condition ? P : never
}[keyof T]
type ConditionalPick<T, Condition> = Pick<T, ConditionalKeys<T, Condition>>
函数插入参数
为已有的函数类型增加指定类型的参数,新增的参数名是 x,将作为新函数类型的第一个参数
type Fn = (a: number, b: string) => number
type AppendArgument<F, A> = // 你的实现代码
type FinalFn = AppendArgument<Fn, boolean>
// (x: boolean, a: number, b: string) => number
点击查看答案
type Fn = (a: number, b: string) => number
// TS 中内置了 Parameters, 和 ReturnType 可以便捷的获取函数的参数和响应类型
type AppendArgument<F extends ((...args: any) => any), A> = (x: A, ...args: Parameters<F>) => ReturnType<F>
type FinalFn = AppendArgument<Fn, boolean>
扁平数组
type NaiveFlat<T extends any[]> = // 你的实现代码
// 测试用例:
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>
// NaiveResult的结果: "a" | "b" | "c" | "d"
点击查看答案
type NaiveFlat<T extends any[]> = {
[P in keyof T]: T[P] extends any[] ? NaiveFlat<T[P]>: T[P]
}[number]
强制对象范围
type SomeType = {
prop: string
}
// 更改以下函数的类型定义,让它的参数只允许严格SomeType类型的值
function takeSomeTypeOnly(x: SomeType) { return x }
// 测试用例:
const x = { prop: 'a' };
takeSomeTypeOnly(x) // 可以正常调用
const y = { prop: 'a', addditionalProp: 'x' };
takeSomeTypeOnly(y) // 将出现编译错误
点击查看答案
type Exclusive<T1, T2 extends T1> = {
[P in keyof T2]: P extends keyof T1 ? T2[P] : never
}
function takeSomeTypeOnly<T extends SomeType>(x: Exclusive<SomeType, T>) { return x }