TypeScript Conditional Types All In One
TypeScript Conditional Types All In One
// SomeType extends OtherType ? TrueType : FalseType;
type SomeType = number;
type OtherType = any;
type TrueType = number;
type FalseType = string;
type Stuff =SomeType extends OtherType ? TrueType : FalseType;
// type Stuff = number
interface IdLabel {
id: number /* some fields */;
}
interface NameLabel {
name: string /* other fields */;
}
function createLabel(id: number): IdLabel;
// function createLabel(id: number): IdLabel (+2 overloads)
function createLabel(name: string): NameLabel;
// function createLabel(name: string): NameLabel (+2 overloads)
function createLabel(nameOrId: string | number): IdLabel | NameLabel;
// function createLabel(nameOrId: string | number): IdLabel | NameLabel (+2 overloads)
function createLabel(nameOrId: string | number): IdLabel | NameLabel {
throw "unimplemented";
}
// function createLabel(id: number): IdLabel (+2 overloads)
// better solution ?
type NameOrId = T extends number ? IdLabel : NameLabel;
function createLabel(idOrName: T): NameOrId {
throw "unimplemented";
}
Conditional Type Constraints
条件类型约束
interface MessageType {
message: unknown;
}
// type MessageOf = T extends MessageType ? T["message"] : never;
// 等价于
type MessageOf = T extends { message: unknown } ? T["message"] : never;
interface Email {
message: string;
}
interface Dog {
bark(): void;
}
type EmailMessageContents = MessageOf;
// type EmailMessageContents = string
type DogMessageContents = MessageOf;
// type DogMessageContents = never
type Flatten = T extends any[] ? T[number] : T;
// array, extracts out the element type
type Str = Flatten;
// type Str = string
type num = Flatten;
// type num = number
// not array, leaves the type alone.
type Num = Flatten;
// type Num = number
type str = Flatten;
// type str = string
Inferring Within Conditional Types
在条件类型中推断
type Flatten = Type extends Array ? Item : Type;
// type Flatten = Type extends (infer Item)[] ? Item : Type
// 可以从函数类型中提取返回类型
type GetReturnType = 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[]
type VoidType = GetReturnType<() => void>;
// type VoidType = void
declare function stringOrNum(x: string): number;
declare function stringOrNum(x: number): string;
// 从具有多个调用签名的类型(例如重载函数的类型)进行推断时,从最后一个签名进行推断(这大概是最宽容的包罗万象的情况)
// 无法根据参数类型列表执行重载决议。
declare function stringOrNum(x: string | number): string | number;
// type ReturnType any> = T extends (...args: any) => infer R ? R : any
type T1 = ReturnType;
// type T1 = string | number
Distributive Conditional Types
可分配条件类型
type ToArray = Type extends any ? Type[] : never;
// union type / 联合类型
type StrArrOrNumArr = ToArray;
// type StrArrOrNumArr = string[] | number[]
type StrArrOrNumArr2 = ToArray | ToArray;
Typically, distributivity is the desired behavior. To avoid that behavior, you can surround each side of the extends
keyword with square brackets
.
通常,分配性是期望的行为。为了避免这种行为,您可以用方括号将 extends 关键字的每一侧括起来。
type ToArrayNonDist = [Type] extends [any] ? Type[] : never;
// 'StrArrOrNumArr' is no longer a union.
type StrArrOrNumArr = ToArrayNonDist;
// type StrArrOrNumArr = (string | number)[]
leetcode TypeScript 面试题
// import { expect } from "chai";
interface Action {
payload?: T;
type: string;
}
class EffectModule {
count = 1;
message = "hello!";
delay(input: Promise) {
return input.then((i) => ({
payload: `hello ${i}!`,
type: "delay"
}));
}
setMessage(action: Action) {
return {
payload: action.payload!.getMilliseconds(),
type: "set-message"
};
}
}
// 修改 Connect 的类型,让 connected 的类型变成预期的类型
// type Connect = (module: EffectModule) => any;
// 1. 过滤出成员属性的函数 ?
type FilterFunction = {
// 仅仅过滤 Function
[K in keyof Obj]: Obj[K] extends Function ? K : never;
}[keyof Obj];
type Connect = (
module: EffectModule
) => {
// 2. 使用 infer 动态获取 参数类型
[K in FilterFunction]: EffectModule[K] extends (
input: Promise
) => Promise>
? (input: T) => Action
: EffectModule[K] extends (action: Action) => Action
? (action: T) => Action
: never;
// ?? input & action 形参必须写死 ???
};
/*
type Connect = (module: EffectModule) => {
delay: (input: number) => Action;
setMessage: (action: Date) => Action;
}
*/
const connect: Connect = (module) => ({
delay: (input: number) => ({
type: "delay",
payload: `hello 2`
}),
setMessage: (input: Date) => ({
type: "set-message",
payload: input.getMilliseconds()
})
});
type Connected = {
delay(input: number): Action;
setMessage(action: Date): Action;
};
export const test = connect(new EffectModule());
/*
type Connect = (module: EffectModule) => {
delay: (input: number) => Action;
setMessage: (action: Date) => Action;
}
*/
export const connected: Connected = connect(new EffectModule());
refs
https://www.typescriptlang.org/docs/handbook/2/types-from-types.html
https://www.typescriptlang.org/docs/handbook/2/conditional-types.html
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html
?xgqfrms 2012-2020
www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!
原创文章,版权所有??xgqfrms, 禁止转载 ???,侵权必究??!