V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
kernel
V2EX  ›  JavaScript

请教一个 typescript 的泛形问题

  •  
  •   kernel · 2018-09-30 21:41:53 +08:00 · 3032 次点击
    这是一个创建于 2249 天前的主题,其中的信息可能已经有所发展或是发生改变。
    export {}
    
    interface Types {
      A: 'A'
      B: 'B'
    }
    
    type GetType = <K extends keyof Types> (k: K) => K
    let f: GetType = k => k
    f('A')
    
    type ReturnType = <K extends keyof Types> () => K
    let f2: ReturnType = () => 'A'
        ^^
    

    为何 f2 处会出错:

    [ts] 'f2' is declared but its value is never read.
    [ts]
    Type '() => "A"' is not assignable to type 'ReturnType'.
      Type '"A"' is not assignable to type 'K'.
    let f2: ReturnType
    
    5 条回复    2018-10-01 16:12:35 +08:00
    noe132
        1
    noe132  
       2018-09-30 23:27:15 +08:00
    我的理解
    K 是类型内的一个类型参数,相当于一个局部类型
    K 这个类型如果没有从参数中捕获,直接使用的话除了 any 其他类型都不是 K,因为没有类型是 K。
    因为 K 并不等于 keyof Types

    type TypeKeys = keyof Types
    type ReturnType = () => TypeKeys
    let f2: ReturnType = () => 'A'

    这样就没有问题。
    kernel
        2
    kernel  
    OP
       2018-10-01 13:31:29 +08:00 via Android
    @noe132 不是限定了 K 必须是 keyof Types 了吗,不需要再从参数中确定了吧
    noe132
        3
    noe132  
       2018-10-01 14:04:53 +08:00
    K 是一个泛型的参数,并不是一个确定的类型
    K extends keyof Types 只是对这个泛型的一个约束
    类型参数 K 要么从函数入参确定,要么定义类型为泛型,从泛型的类型参数中获取
    你这两个都没有,K 相当于是一个未知类型。
    noe132
        4
    noe132  
       2018-10-01 14:10:24 +08:00
    你把 K extends key of Types 改成 K extends any 都没有用的。因为没有类型是 K。
    banxi1988
        5
    banxi1988  
       2018-10-01 16:12:35 +08:00
    我尝试了一下。
    首先使用一个有意思的 Interface 稍微调整了一下代码。

    ```ts
    interface Person {
    name: string;
    age: number;
    }
    type PersonProp = keyof Person;
    type PersonPropIdentity = <K extends PersonProp>(prop: K) => K;
    let personPropIdentity: PersonPropIdentity = k => k;
    type FunType1 = <K extends PersonProp>() => K;
    let f2: FunType1 = () => {
    return "age";
    };
    ```
    此时 FunType1 展开之后其实是 :
    type FunType1 = <K extends "name" | "age">() => K
    此时 f2 返回 "age" 应该是符合 K 类型的限定的。 因此我倾向为认为这是 TypeScript 类型系统一个 Bug.
    可以给 TypeScript 反馈一下。

    另外在这种情况下主要是 K extends 影响了类型的推断,不用 K extends 即可。
    如下代码是没有编译错误的。


    ```ts
    type FunType2 = () => PersonProp;
    let f3: FunType2 = () => {
    return "age";
    };
    ```
    而且在 f3 的函数声明来看使用 K extends PersonProp 是没有意义的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3264 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 12:28 · PVG 20:28 · LAX 04:28 · JFK 07:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.