dependent type 和 typescript
dependent type 所解决的问题很好理解:
如果 C 语言是静态强类型语言,printf 这个函数的函数签名是什么?
printf("%s", str);
printf("%d", integer);
很有意思的是,前序参数的值会影响后序参数的类型。
但是这玩意有啥用呢?
如果我们有一种统一的方式可以描述这种函数的类型签名,那么我们用户就可以很容易定义这样的函数,并且借助类型系统,给出更好的代码补全。
例子还是来源于知乎一篇著名的文章(几乎中文社区谈到 ts 的 dependent type 都会提到 zhihu)
interface FooParams {
type: 'foo';
value: string;
}
interface BarParams {
type: 'bar';
value: number;
}
type Params = FooParams | BarParams;
function test<TParams extends Params>(
type: TParams['type'],
value: TParams['value'],
): void {}
这样依然不可以达到我们的目的,因为 test('foo', 1)
这样的调用依然对于类型系统是合法的。ts
并没有对 TParams['type']
和 TParams[''value]
产生关系,他们甚至可以是不同的类型。(这其实是很怪异的)
function test<TType extends Params['type']>(
type: TType,
value: Extract<Params, {type: TType}>['value'],
): void {}
解法是上面这样的。Extract 泛型的功能如下
type U1 = "a" | "b" | "c";
type U2 = "a" | "f";
type T0 = Extract<U1, U2>; // T0 == "a" typescript有值类型的语法
这样就有了 dependent type 的构造方法。
实际上这是假的 dependent type,因为前面的字符串字面量在 typescript 仍然是一个类型,不过这样确实达到了我们的目的。