美文网首页Web前端之路Web 前端开发 我爱编程
理解TypeScript中的一个(伪)黑魔法

理解TypeScript中的一个(伪)黑魔法

作者: Huisama | 来源:发表于2017-02-23 20:13 被阅读1482次

    理解TypeScript中的一个(伪)黑魔法

    最近在学习TypeScript的时候,看到高级类型这里,对

    function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
        return names.map(n => o[n]);
    }
    
    interface Person {
        name: string;
        age: number;
    }
    
    let person: Person = {
        name: 'Jarid',
        age: 35
    };
    
    let strings: string[] = pluck(person, ['name']); 
    

    这段代码有点不太理解,感觉像是黑魔法一般,主要的疑惑点在于:

    let strings: string[] = pluck(person, ['name']);
    

    这段代码,传入给pluck的应该是一个string[],那么泛型函数

    function pluck<T, K extends keyof T>(o: T, names: K[]): TK;
    

    这个签名应该被替换为,

    function pluck<Person, string extends keyof Person>(o: Person, names: string[]): Person[string][];
    

    其中

    keyof Person
    

    等价于

    'name' | 'age'
    

    于是对于约束:

    string extends 'name' | 'age'
    

    而言,就是绝对通不过静态类型检查的,但是在这里却是能够通过的,这让我百思不得其解。

    后来我怀疑自己看漏了什么重要的东西,于是把文档往上翻,在字符串字面量类型这里,看到了一点端倪,于是我在TypeScript中做了这样子的尝试:

    type MyType = 'myType';
    function bar(param : MyType[]) : void {
        console.log(param);
    }
    bar(['myType']);
    

    结果是输出了:

    ["myType"]

    于是我恍然大悟,在前面的代码中TypeScript的类型约束事实上是做了这样子的工作:

    1. 通过

      keyof Person
      

      获得了

      "name" | "age"
      
    2. 根据

      K extends keyof Person
      

      约束了K要么是“name”要么是“age”**

      假设如果两者都不是,那么静态检查将会直接报错;

    3. 现在静态检查器来检查

      names : K[]
      

      由于传入的是['name'],那么首先如果将其解释为string[]的话显然是不对的,那么进一步地,TypeScript静态检查器尝试将['name']中的'name'看成是一个字符字面量类型,然后将其解释为'name'[],即字符字面量类型数组,这样一来,泛型变量K就是'name',约束'name' extends 'name' | 'age'就顺利通过了。**

    4. 进一步的,T[K]事实上就是Person['name'],而Person['name']就是string所以这个函数的返回值就是string[]

    为了验证我的猜想,我把最后那行调用改成了

    let strings: string[] = pluck(person, ['name', 'name', 'name']); 
    

    然后测试的时候输出:

    ["Jarid", "Jarid", "Jarid"]

    这符合我的理解。

    总结一下,其实理解这个问题最大的关键就是理解TypeScript字符串字面量类型这个概念,这个概念使得TypeScript的静态检查变得相当灵活,从上面的描述我们可以看出'name'这个字符串使得TypeScript静态分析的时候做了一定的推断(可能推断过程和我的描述并非一致,因为我还没有仔细研读过TypeScript的源代码),这使得我们在阅读TypeScript源代码的时候需要额外地注意这样一些灵活之处。

    相关文章

      网友评论

        本文标题:理解TypeScript中的一个(伪)黑魔法

        本文链接:https://www.haomeiwen.com/subject/gfabwttx.html