
先上代码
export interface Store { [key: string]: any; } type OnFinishCallback= (values: Store) => void; export interface Callbacks { onFinish?: OnFinishCallback; } export interface TestData { name: string; password: string; age: number; } const test1: OnFinishCallback= (values: TestData) => {}; const test2: Callbacks['onFinish'] = (values: TestData) => {}; 抛出问题

Typescript 版本:3.7.5
提问:为什么不能匹配泛型接口?单纯好奇,也知道可以通过 <T> 或者中间函数传递来解决。
1 johnnyNg 2020 年 3 月 3 日 说的是 TestData 和 Store 类型不符合,把 TestData 改成 Store 就好了 |
2 mxT52CRuqR6o5 2020 年 3 月 3 日 via Android 泛型在哪? |
3 HanMeiM OP @mxT52CRuqR6o5 害,俺说错了,泛型能匹配上,但是直接这样写 索引签名 不行。 |
4 chuxiaonan 2020 年 3 月 3 日 export interface TestData extends Store { ... } |
5 HanMeiM OP @chuxiaonan 不行哦,我试过的。 |
6 chuxiaonan 2020 年 3 月 3 日 @HanMeiM 这样噢 那就不是很了解啦 |
7 myl0204 2020 年 3 月 3 日 我的理解是实际函数的参数类型是确定的:`TestData `,而 OnFinishCallback 中参数类型其实是不定的,可以是`{a: 1, b:2}`也可以是`{c: 3}`等等。 这二者当然不匹配呀 |
8 maichael 2020 年 3 月 3 日 因为 Store 类型的值不能赋值给 TestData 类型的变量。你对泛型的理解是有问题的,你想,假设你整个逻辑成立,那你这里的 test1 函数入参就是 Store 类型的变量,但是 Store 类型的变量未必能赋值给 TestData 类型的变量,所以逻辑上不通。反过来才是对的,但意图就可能跟你原有的不一致了,你可以说下你的需求是啥吗 type OnFinishCallback= (values: TestData) => void; const test1: OnFinishCallback= (values: Store) => {}; |
9 geelaw 2020 年 3 月 3 日 Store 是水果,TestData 是橘子,OnFinishCallback 是“能处理任意水果”的类型。因为 test1 初始化的表达式不能处理任意水果(只能处理橘子),所以不行。 用术语来说是 A => void 对 A 是逆变,如果 is-an A,则 (A => void) is-a (B => void),而不是反过来。 |
10 HanMeiM OP @maichael @geelaw 其实也不是我写成这样,我肯定还是希望用泛型去解决。 我还是直接说我在哪遇到的问题吧。 我今天更新 Ant-Design 4.0.0 的时候,Form 组件有很大的改变。 官方推荐使用 `Form` 组件的 `onFinish` 属性来获取表单值。 下面是这个属性的定义。    然后上图的 `test2` 就是我写的获取表单的方法,很明显会报错,所以有点头疼。 目前是直接在 `Form` 表单中这样写来解决 ```Typescript OnFinish={(value: Store) => test2(value)} ``` |
11 maichael 2020 年 3 月 3 日 @HanMeiM #10 暂时没有,这个 Antd 这个东西的问题。 https://github.com/ant-design/ant-design/issues/21195 https://github.com/react-component/field-form/issues/70 简单来说,他这里本应该提供 "Generic type arguments" 来自定义 StoreValue 的类型,但他没有给,所以你从外部没法去改变他内部的类型。你现在只能强转类型然后等他修好。 |
13 buffzty 2020 年 3 月 3 日 TestData 类型是兼容 Store 的,但是 (v: TestData )=>{} 这个函数类型 是不兼容 (v: Store)=>{} 这个函数类型的 可能是 ts 为了检测简单,不然还要把所有函数的参数再检测一遍. 我的建议: 去掉函数形参中的类型,此时 ts 会自动推断为 Store 传参时可以传 TestData 类型. 以下代码在 3.7.5 无报错 ```typescript export interface Store { title: string // 加这个只是为了测试自动推断 [key: string]: any } type OnFinishCallback= (values: Store) => void export interface Callbacks { onFinish?: OnFinishCallback } export type TestData = Store & { name: string password: string age: number } let a: TestData = { b: 123, age: 12, name: '1', password: '', title: '' } let b: Store = a const test1: OnFinishCallback= values => { console.log(values.title) // 这里的 values 已经被自动推断过了 } const test2: Callbacks['onFinish'] = values => { console.log(values.title) } test1(a) test1(b) test2(a) test2(b) ``` |
14 Mistwave 2020 年 3 月 3 日 |
17 voidcomma 2020 年 3 月 3 日 TestData 的类型显然更具体了,它的类型被收窄(narrow down)了,test1 中的 values 的限制更多,不匹配 OnFinishCallback 中的 Store。也就是,OnFinishCallback 的 values 参数能够接受任意的对象,而你给 test1 的 values 定义的参数中只能包含 name, password, age 这三个属性。 不需要给 test1 中的 values 定义类型 TestData,它会被推断为 Store。 |
18 buffzty 2020 年 3 月 3 日 @HanMeiM 为什么去掉形参类型名叫放弃优势呢? 去掉之后什么代码也没多写,类型也自动推断了. 你不就是要这个效果吗 本来能自动推断的,你非要给他加个错误类型 |
19 HanMeiM OP @buffzty 很明显这个 Store 应该是个泛型,只不过他这里写的有问题。你实际写代码的时候,看你代码的人能通过 Store 知道什么呢?我能知道这个表单有哪些数据?这个数据是什么类型?我还是得看上下文代码。 |
20 maichael 2020 年 3 月 4 日 @HanMeiM #12 const test1: OnFinishCallback= ((values: TestData) => {}) as OnFinishCallback 一个勉强用着的解决方法。 |
21 jchencode 2020 年 5 月 17 日 老哥,想问下你们 [email protected] 怎么用 ts 写表单,有代码可以参考下吗,感谢! |
22 HanMeiM OP @LiuJiang 我个人是这么写的 const handleFinish = (fieldsValue: IFieldsValue) => { ... } <Form OnFinish={(value: any) => handleFinish(value)}> ... </Form> |
25 uxstone 2020 年 7 月 14 日 Antd V4 文档中的示例代码 TypeScript 和 Javascript 是一样的 蛋疼,感觉与 TypeScript 整合这块还没有 V3 的好用 |