一个简单的函数
function func<T>(data: T): T {
return data;
}
// 调用
const val = func<string>('hello');
// 自动推导调用
const val1 = func('hello');
你可以声明类型参数来约束其他类型参数。例如:
function getValue<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, 'a');
getProperty(x, 'm'); // error
type obj = { test: 'test'; str: 'str' };
type key = keyof obj;
const keys: key = 'a'; // error
const keys: key = 'test'; // correct
typeof 可以返回参数的类型
let h = 'hello';
type t = typeof h; // type t = string
ReturnType
type func = () => boolean;
type funcType = ReturnType<func>; // type funcType = boolean
const f = () => { a: 1, b: 2 }
type fType = ReturnType<typeof f> // type fType = { a: number, b: number }
type Person = { age: number; name: string; alive: boolean };
type Age = Person['age']; // type Age = number
type T1 = Person['age' | 'name']; // type T1 = number | string
条件类型于三目运算符
类似,表达式如下:
someType extends OtherType ? TrueType : FalseType
文字表达如下:如果一个类型继承于某个其他类型,则为 true,否则 false
For Instance:
interface Animal {
live(): void;
}
interface Dog extends Animal {
woof(): void;
}
type Example1 = Dog extends Animal ? number : string; // type Example1 = number
type Example2 = RegExp extends Animal ? number : string; // type Example2 = string
有时候我们需要根据输入类型的不同而返回对应的类型,例如以下这个函数:
interface IdType = {
id: number
}
interface NameType = {
name: string
}
function createLabel(id: number): IdType;
function createLabel(name: string): NameType;
function createLabel(idOrName: number | string): IdType | NameType ;
function createLabel(idOrName: number | string): IdType | NameType {
// doing something
}
上面例子通过重载,根据参数的不同类型,返回不同的数据,可以看出函数非常复杂。这里可以使用条件类型替换他:
interface IdType = {
id: number
}
interface NameType = {
name: string
}
type IdOrName<T extends string | number> = T extends string ? NameType : IdType
function createLabel<T extends string | number>(key: T): IdOrName<T> {
// do something
}
type MessageOf<T> = T['message']; // error
上面例子中,泛型 T 不知道是否有一个叫 message 的属性,所以报错了,我们必须约束泛型 T,让他能支持 message 这个属性:
type MessageOf<T extends { message: unknown }> = T['message'];
interface Email {
message: string;
}
type EmailMessageContents = MessageOf<Email>; // type EmailMessageContents = string
如果属性中没有message
这个属性,则需要返回 never,这时我们可以使用条件类型取约束
type MessageOf<T> = T extends { message: unknown } ? T['message'] : never;
interface Email {
message: string;
}
interface Dog {
bark(): void;
}
type EmailMessageContents = MessageOf<Email>; // type EmailMessageContents = string
type DogMessageContents = MessageOf<Dog>; // type DogMessageContents = never
type Flatten<Type> = Type extends Array<infer Item> ? Item : Type;
type T1 = Flatten<string[]>; // type T1 = string
type T2 = Flatten<number>; // type T2 = number
type GetReturnType<Type> = Type extends (...args: never[]) => infer Return
? Return
: never;
type Num = GetReturnType<() => number>; // type Num = number
type Str = GetReturnType<(x: string) => string>; // type Str = string
type Bools = GetReturnType<(a: boolean, b: boolean) => boolean[]>; // type Bools = boolean[]
When conditional types act on a generic type, they become distributive when given a union type
当条件类型用作分配时,他们会使联合类型变得可分配????看不懂,直接上代码
type ToArray = Type extends any ? Type[] : never;
type T1 = ToArray; // type T1 = string[] | number[]
type ToArrayNonDist = [Type] extends [any] ? Type[] : never; // type StrArrOrNumArr = ToArrayNonDist;
当你不想做重复的工作,有时候类型需要基于一些其他类型
映射类型用于声明未提前声明的属性类型, For Example:
type T = {
[key: string]: string | number;
};
const test: T = {
test1: 'hello',
test2: 1234,
};
映射类型是一种通用类型,也可以配合keyof
使用去创建一些类型
type Type = {
test1: string;
test2: number;
};
type Type2<T> = {s
[key in keyof T]: boolean;
};
type Rest = Type2<Type> // type Rest = { test1: boolean, test2: boolean }
当我我们添加映射时,有两个额外的操作符可以修改:readonly
和 ?
type CreateType<Type> = {
-readonly [Key in keyof Type]: Type[Key];
};
type LockType = {
readonly test1: string;
readonly test2: string;
};
type UnLockType = CreateType<LockType>; // type UnLockType = { test1: string, test2: string }
type CreateMustType<Type> = {
[Key in keyof Type]-?: Type[Key];
};
type maybeType = {
test1?: string;
test2?: string;
};
type MustType = CreateMustType<maybeType>; // type MustType = { test1: string, test2: string }
在 Typescript 4.1
中,你可以用as
来重新定义映射名。
语法:
type RemapType<Type> = {
[Key in keyof Type as newKey]: Type[Key];
};
例如:
// Capitalize 首字母大写
type AddGetName<Type> = {
[Key in keyof Type as `get${Capitalize<string & Key>}`]: Type[Key];
};
type TestType = {
test1: string;
test2: string;
};
type AddTestType = AddGetName<TestType>;
// type AddTestType = { getTest1: string, getTest2: string }
与 es6 模板字符串类似
type Type1 = 'World';
type Hello = `Hello ${Type1}`; // type Hello = "Hello World"