原文:How to master advanced TypeScript patterns
Learn how to create types for curry and Ramda
const toCurry = (name:string, age:number,single: boolean) => trueconst curried = curry(toCurry);const test0 = curried('Jane')('26', true);const test1 = curried(R._, 26)('Jane', R._)(R._)([true])
What is currying?
柯里化是指把一个带有多个参数的函数转成每次执行都只有一个参数的过程。如下所示:
const sampleAdd = (a: number, y: number) => x + y;const test00 = sampleAdd(4, 6) // 10
sampleAdd的柯里化版本如下:
const curriedAdd = (x: number) => (y: number) => x + y;const test01 = curriedAdd(4)(2); // 6const test02 = curriedAdd(15); // Functionconst test03 = test02(5); // 20
Tuple types
Tuple允许你定义个一个数组,并具有固定数量/类型的元素。
type tuple = ['a', number, string[]];
它们可用于在固定大小的数组中强制这种类型的值。
const test04: tuple = ['a', 1, ['b', 'c']];
也可以用于剩余参数的联合或者解构:
const test05 = (...args: tuple) => trueconst test06 = test05('a', 42, []);
一个基础的函数:
const fn00 = (name: string, age: number, single: boolean) => true;const test07 = Parameters<typeof fn00> // [string, number, boolean]
感谢Parameters的魔法,我们可以从fn00提取参数类型。
一个更复杂的例子:
type Params<F extends (...args: any[]) => any> =F extends ((...args: infer A) => any)? A: never
验证下:
type test08 = Params<typeof fn00> //[string, number, boolean]
Head
Head通过获取tuple 类型 T,并且返回tuple里面的第一个类型。
type Head<T extends any[]> =T extends [any, ...any[]]? T[0]: never
验证下:
type test9 = Head<[1, 2, string, number]>; // 1type test10 = Head<Params<typeof fn00>>; // string
Tail
一个经典的柯里化函数通过一个接一个的消费参数。这意味着当我们消费Head<Params<F>>,一般情况下 我们还要消费下一个参数在函数还没有调用完成时。这就是Tail的目的,他可以轻松的删除掉tuple中的第一个实体。
type Tail<T extends any[]> =((...t: T) => any) extends ((_: any, ...tail: infer TT) => any)? TT: []
测试一下:
type test11 = Tail<[1, 2,string,number]> // [2, string, number]type test12 = Tail<Params<typeof fn00>> // [number, boolean]type test13 = Tail<test12> // [boolean]
HasTail
一个柯里化函数直到消费完所有的参数后就返回一个函数。这种情况我们把它叫做Tail,直到没有参数可以被消费。
type HasTail<T extends any[]> =T extends ([] | [any])? false: true
测试一下:
type params = [string, number];type test14 = HasTail<params>;type test15 = HasTail<Tail<params>>type test16 = HasTail<Tail<Tail<params>>>
Important keywords
有三个重要的关键字:type,extends 和infer
extends:type:infer:
Extract a property’s type from an object
从一个对象中提取属性的类型
type Objectinfer<O> =O extends {a: infer A}? A // if true: never // if false
测试一下:
const object = {a: 'hello'};const test17 = Objectinfer<typeof object>; // stringconst test18 = Objectinfer<string>; // never
Extract inner types from function types
从函数类型里提取类型。
type FunctionInfer<F> =F extends (...args: infer A) => infer R? [A: R] // if true: never // if false
测试一下
const fn01 = (a: number, b: any) => anytype test19 = FunctionInfer<typeof fn01> // [[number, any],any]
Extract generic types from a class or an interface
从一个类或者接口中提取泛型类型
type ClassInfer<I> =I extends Promise<infer G>? G // if true: never // if false
测试一下
const promise = new Promise<string>(() => {})type test20 = ClassInfer<typeof promise> //string
Extract types from an array
从数组中提取类型
type ArrayInfer<> =T extends (infer U) []? U // if true: never // if false
测试一下:
const array = [0, 'data', 1, 'data'];type test21 = ArrayInfer<typeof array> // string | number
Extract types from a tuple
从tuple中提取类型
type TupleInfer <T> =T extends [infer A ,...(infer B)[]]? [A, B]: never
测试一下:
type test22 = TupleInfer<[string, number, boolean]>// [string, number | boolean]
