请教一个 typescript 的泛形问题

2018-09-30 21:41:53 +08:00
 kernel
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
3029 次点击
所在节点    JavaScript
5 条回复
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
2018-10-01 13:31:29 +08:00
@noe132 不是限定了 K 必须是 keyof Types 了吗,不需要再从参数中确定了吧
noe132
2018-10-01 14:04:53 +08:00
K 是一个泛型的参数,并不是一个确定的类型
K extends keyof Types 只是对这个泛型的一个约束
类型参数 K 要么从函数入参确定,要么定义类型为泛型,从泛型的类型参数中获取
你这两个都没有,K 相当于是一个未知类型。
noe132
2018-10-01 14:10:24 +08:00
你把 K extends key of Types 改成 K extends any 都没有用的。因为没有类型是 K。
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 是没有意义的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/494287

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX