Open sufuwang opened 1 year ago
type Func = (obj: 1, other: 'other') => void
type MyParameters<Fn> = Fn extends (...args: infer T) => any ? T : any
// [obj: 1, other: "other"]
type P1 = Parameters<Func>
type P2 = MyParameters<Func>
type Func = (obj: 1, other: 'other') => [1, 'A']
type MyReturnType<Fn> = Fn extends (...args: any) => infer T ? T : any
// [1, "A"]
type P1 = ReturnType<Func>
type P2 = MyReturnType<Func>
interface Func1 {
new (obj: 1, other: 'other'): [1, 'A']
}
type Func2 = new (obj: 1, other: 'other') => [1, 'A']
type MyConstructorParameters<Fn extends abstract new(...args: any) => any> =
Fn extends new (...args: infer T) => any ? T : any
// [obj: 1, other: "other"]
type P1 = ConstructorParameters<Func1>
type P2 = MyConstructorParameters<Func1>
type P3 = ConstructorParameters<Func2>
type P4 = MyConstructorParameters<Func2>
interface Func1 {
new (obj: 1, other: 'other'): [1, 'A']
}
type Func2 = new (obj: 1, other: 'other') => [1, 'A']
type MyInstanceType<Fn extends abstract new(...args: any) => any> =
Fn extends new (...args: any) => infer T ? T : any
// [1, "A"]
type P1 = InstanceType<Func1>
type P2 = MyInstanceType<Func1>
type P3 = InstanceType<Func2>
type P4 = MyInstanceType<Func2>
interface Person {
name: string;
age: number;
}
type MyThisParameterType<Fn extends (this: any, ...args: any) => any> =
Fn extends (this: infer T) => any ? T : unknown
type Func = (this: Person) => void
// Person
type P1 = ThisParameterType<Func>
type P2 = MyThisParameterType<Func>
interface Person {
name: string;
age: number;
}
type MyOmitThisParameter<Fn extends (this: any, ...args: any) => any> =
Fn extends (this: any, ...args: infer T) => infer R ? (...args: T) => R : unknown
type Func = (this: Person, name: Person['name'], age: 12) => Person
// (name: string, age: 12) => Person
type P1 = OmitThisParameter<Func>
type P2 = MyOmitThisParameter<Func>
interface Person {
name: string;
age: number;
}
type MyPartial<T extends Record<any, any>> = {
[K in keyof T]?: T[K]
}
// { name?: string | undefined; age?: number | undefined; }
type P1 = Partial<Person>
type P2 = MyPartial<Person>
interface Person {
name: string;
age: number;
}
type PartialPerson = Partial<Person>
type MyRequired<T extends Record<any, any>> = {
[K in keyof T]-?: T[K]
}
// { name: string; age: number; }
type P1 = Required<PartialPerson>
type P2 = MyRequired<PartialPerson>
interface Person {
name: string;
age: number;
}
type MyReadonly<T extends Record<any, any>> = {
readonly [K in keyof T]: T[K]
}
// { name: string; age: number; }
type P1 = Readonly<Person>
type P2 = MyReadonly<Person>
interface Obj {
a: 'A';
b: 'B';
1: '1';
2: '2';
}
type MyPick<O extends Record<string, any>, KeyS extends keyof O> = {
[Key in KeyS]: O[Key]
}
// { a: 'A'; 1: '1'; }
type a = Pick<Obj, 'a' | 1>
type b = MyPick<Obj, 'a' | 1>
// string | number | symbol
type a = string | number | symbol
type b = keyof any
type MyRecord<K extends keyof any, T> = {
[Key in K]: T
}
// { 1: void; a: void; }
type P1 = Record<1 | 'a', void>
type P2 = MyRecord<1 | 'a', void>
type MyExclude<K extends keyof any, T> = K extends T ? never : K
// symbol | "a"
type P1 = Exclude<1 | 'a' | symbol, 1>
type P2 = MyExclude<1 | 'a' | symbol, 1>
type MyExtract<K extends keyof any, T> = K extends T ? K : never
// symbol | 1
type P1 = Extract<1 | 'a' | symbol, 1 | symbol>
type P2 = MyExtract<1 | 'a' | symbol, 1 | symbol>
interface Person {
name: string;
age: number;
}
type MyOmit<K extends Record<string, any>, T> = Pick<K, Exclude<keyof K, T>>
// { age: number; }
type P1 = Omit<Person, 'name'>
type P2 = MyOmit<Person, 'name'>
type MyAwaited<T extends Promise<any>> =
T extends Promise<infer K>
? K extends Promise<any> ? MyAwaited<K> : K
: T
// [1]
type P1 = Awaited<Promise<[1]>>
type P2 = MyAwaited<Promise<[1]>>
type P3 = Awaited<Promise<Promise<[1]>>>
type P4 = MyAwaited<Promise<Promise<[1]>>>
type P5 = Awaited<Promise<Promise<Promise<[1]>>>>
type P6 = MyAwaited<Promise<Promise<Promise<[1]>>>>
type MyNonNullable<T> = T extends null | undefined ? never : T
// Promise<[1]>
type P1 = NonNullable<Promise<[1]>>
type P6 = MyNonNullable<Promise<[1]>>
// never
type P2 = NonNullable<null>
type P3 = NonNullable<never>
type P4 = NonNullable<undefined>
type P7 = MyNonNullable<null>
type P8 = MyNonNullable<never>
type P9 = MyNonNullable<undefined>
// void & {}
type P5 = NonNullable<void>
// void
type P10 = MyNonNullable<void>
/**
* Construct a type with a set of properties K of type T
*/
type Record<K extends keyof any, T> = {
[P in K]: T;
};
type a = keyof any // string | number | symbol
/**
* Exclude from T those types that are assignable to U
*/
type Exclude<T, U> = T extends U ? never : T;
/**
* T(1) extends 1 ? never : T ==> never
* T('a') extends 1 ? never : T ==> 'a'
* T(symbol) extends 1 ? never : T ==> symbol
*/
type a = Exclude<1 | 'a' | symbol, 1> // symbol | "a"
/**
* Construct a type with the properties of T except for those in type K.
*/
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
type MyOmit<T, U> = {
[key in keyof T as key extends U ? never : key]: T[key]
}
Differences Between Type Aliases and Interfaces
Type aliases and interfaces are very similar, and in many cases you can choose between them freely. Almost all features of an
interface
are available intype
, the key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable.类型别名和接口非常相似,在很多情况下您可以在它们之间自由选择。 接口的几乎所有功能都可以在类型中使用,关键区别在于类型不能重新打开以添加新属性,而接口始终是可扩展的。
type T1 = {
a: 'A'
}
type T2 = {
b: 'B'
}
type T = T1 & T2
interface I {
a: 'A'
}
interface I {
b: 'B'
}
const t1: T = { a: 'A', b: 'B' }
const t2: I = t1
协变指的是子类型变量可以赋值给父类型
interface Parent {
name: string
age: number
}
interface Son extends Parent {
tel: string
}
const s1: Son = {
name: '1',
age: 1,
tel: '1'
}
const p1: Parent = s1 // 子类型满足父类型约束
const p2: Parent = {
name: '1',
age: 1,
}
// TS2741: Property 'tel' is missing in type 'Parent' but required in type 'Son'
const s2: Son = p2 // 父类型不满足子类型约束
或者这个例子更容易理解一些
type Son = string;
type Parent = keyof any;
let s: Son = "";
let p: Parent = 1;
// Type 'number' is not assignable to type 'string'.ts(2322)
s = p;
p = s;
逆变指的是父类型函数参数可以赋给子类型函数参数
interface Parent {
name: string
age: number
}
interface Son extends Parent {
tel: string
}
type ParFn = (arg: Parent) => void
type SonFn = (arg: Son) => void
let p: ParFn = (p) => p.name
let s: SonFn = (s) => s.tel
s = p // 父类型一定满足子类型约束
s = (p) => p.name
/**
* TS2322: Type 'SonFn' is not assignable to type 'ParFn'.
* Types of parameters 'arg' and 'arg' are incompatible.
* Property 'tel' is missing in type 'Parent' but required in type 'Son'.
*/
p = s // 子类型的实现可能超出父类型约束
p = (s) => s.tel
函数返回参数执行协变
interface Parent {
name: string
age: number
}
interface Son extends Parent {
tel: string
}
type ParFn = () => Parent
type SonFn = () => Son
let p: ParFn = () => ({}) as Parent
let s: SonFn = () => ({}) as Son
/**
* TS2322: Type 'ParFn' is not assignable to type 'SonFn'.
* Property 'tel' is missing in type 'Parent' but required in type 'Son'.
*/
s = p // 返回参数子类型可以付给父类型
p = s
逆变的影响
type GetReturnType_A<Fn> = Fn extends (...args: unknown[]) => infer T ? T : never
type GetReturnType_B<Fn> = Fn extends (...args: any[]) => infer T ? T : never
// never
type G1 = GetReturnType_A<(a: 'A') => 1>
// 1
type G2 = GetReturnType_B<(a: 'A') => 1>
逆变的用途
type UnionToIntersection<U> =
(U extends U ? (arg: U) => void : never) extends (arg: infer R) => void ? R : never
// {a: "A"} & {b: "B"}
type A = UnionToIntersection<{a:'A'} | {b:'B'}>
只要不是父子类型的系统,就不可以相互赋值。在
java
中使用extends
关键字确立父子关系的,这种被称为名义类型系统,而typescript
是结构类型系统,即结构上是一致的就可以确立父子关系
在 typescript
中,类型描述更具体的则是子类型,举两个例子
协变表示子类型可以赋值给父类型,父类型不可以赋值给子类型,因为子类型中存在父类型不存在的类型声明,所以 TypeA
是父类型,TypeB
是子类型
interface TypeA {
name: string
age: number
}
interface TypeB {
name: string
age: number
tel: string
}
let a: TypeA = {} as TypeA
let b: TypeB = {} as TypeB
a = b
// TS2741: Property 'tel' is missing in type 'TypeA' but required in type 'TypeB'.
b = a
逆变表示子类型参数的函数不能赋值给父类型参数的函数,因为子类型包含一些父类型不存在类型声明,具体执行的时候可能会出错,所以 TypeA
是父类型,TypeB
是子类型。TypeA
有三种可能,TypeB
只有其中的两种,所以 TypeB
更加具体,也可以说明 TypeB
是子类型
type TypeA = 1 | 2 | 3
type TypeB = 1 | 2
type FuncA = (arg: TypeA) => void
type FuncB = (arg: TypeB) => void
let a: FuncA = () => null
let b: FuncB = () => null
b = a
/**
* TS2322: Type 'FuncB' is not assignable to type 'FuncA'.
* Types of parameters 'arg' and 'arg' are incompatible.
* Type 'TypeA' is not assignable to type 'TypeB'.
* Type '3' is not assignable to type 'TypeB'.
*/
a = b
双向协变指的是函数参数不受逆变限制,带有父子类型参数的函数可以相互赋值,只需要一个设置 strictFunctionTypes 即可
学习一下 ts 零碎的知识点