请问 typescript 类型声明问题?

2020-01-04 14:20:02 +08:00
 xiaoming1992
type TA = "typeA"
type TB = "typeB"
type TC = "typeC"

type HA = (arg: number) => void;
type HB = (arg: string) => void;
type HC = (arg: boolean) => void;

// 目的是为了实现下面这样类似的重载
// 但是感觉重载有些麻烦,万一类型多了,得写一堆,很烦
// 有什么办法通过泛型来表达吗?
function func(type: TA, handler: HA): void;
function func(type: TB, handler: HB): void;
function func(type: TC, handler: HC): void;
2329 次点击
所在节点    程序员
16 条回复
wisebeer
2020-01-04 14:33:58 +08:00
用 any
xiaoming1992
2020-01-04 14:47:41 +08:00
@wisebeer 大佬!大佬![抱拳]
des
2020-01-04 15:14:09 +08:00
泛型
EridanusSora
2020-01-04 15:36:31 +08:00
type H<T> = (arg: T) => void;

function funcA(type: TA, handler: H<string>): void;
function funcB(type: TB, handler: H<number>): void;
function funcC(type: TC, handler: H<boolean>): void;
codelegant
2020-01-04 15:37:30 +08:00
TA | TB | TC 与 HA | HB | HC 之前可以通过操作关联起来吗?如果不行,就无法使用泛型。泛型就是用变量捕获类型的声明,然后重用。
wi
2020-01-04 20:24:07 +08:00
interface TMap {
"a": (a: number) => any
"b": (b: number | string) => any
"c": (c: Date) => any
}

function fn2<T extends keyof TMap, F extends TMap[T]>(a: T, fn: F) {

}
wi
2020-01-04 20:26:44 +08:00
function fn3<T extends keyof TMap>(a: T, fn: TMap[T]) {

}
这个也可以
xiaoming1992
2020-01-04 21:19:46 +08:00
@EridanusSora 我就是不想用重载啊...

@wi 真·大佬!我一直在想前面的 T 怎么限定,大佬一个 extends 就解决了,感谢!
a132811
2020-01-05 09:29:37 +08:00
@wi 请问这里怎么错了啊?

```
$ cat a.ts
interface TMap {
"a": (a: number) => any
"b": (b: number | string) => any
"c": (c: Date) => any
}

function fn2<T extends keyof TMap, F extends TMap[T]>(a: T, fn: F) {
console.log(a, fn(1))

}

fn2("a",(a:number)=>a)
➜ ts$ git:(master) ✗
$ tsc a.ts
a.ts:8:27 - error TS2345: Argument of type '1' is not assignable to parameter of type 'number & Date'.
Type '1' is not assignable to type 'Date'.

8 console.log(a, fn(1))

```
xiaoming1992
2020-01-05 09:41:52 +08:00
@a132811 你这个 fn(1),TMap["c"]是不能接受 1 这个参数的啊。你是 abc 看懵了吧,把 fn2 里面的参数 a 改成 w 或者其他什么符号就清楚一点了
a132811
2020-01-06 00:13:29 +08:00
@xiaoming1992 你没有看懵了,我确实是不明白。
我的代码里面 fn 的类型就是 TMap["a"]吧,也就是(a: number) => any 吧

fn(1) 中 1 与 a:number 应该能匹配类型才对呀
a132811
2020-01-06 00:14:13 +08:00
你没有看懵了-〉我没有看懵
xiaoming1992
2020-01-06 00:42:38 +08:00
@a132811 TMap["a"]确实没问题,可是 TMap["c"]是有问题的啊。你在定义 fn2 的时候,console.log(a, fn(1)),不能 fn(1),因为 fn 可能只能接受 Date,你把函数的形参全部改成 w,就能发现自己哪里的问题了
xiaoming1992
2020-01-06 00:48:27 +08:00
interface TMap {
"a": (w: number) => any
"b": (w: number | string) => any
"c": (w: Date) => any
}

function fn2<T extends keyof TMap, F extends TMap[T]>(w: T, fn: F) {
// 这儿错了,不能直接调用 fn(1)
// 当 w == "c"时,fn 不能接受 1 作为参数
console.log(w, fn(1))
}

// 你看看,如果上面执行 fn(1)
// 那你这么调用是不是就 errer 了?
fn2("c", (w: Date) => w.getDate())

// 手机打字好累...
a132811
2020-01-06 10:00:30 +08:00
@xiaoming1992 感谢!
我才想明白,我想成了把 fn:F 想成了执行时 `fn2("a", (n:number)=>n)` 才确定类型 为 number

其实编译 typescript 时, fn:F 的类型就确定必须接受: number|string|Date,少一个都不行

ps:程序员不要熬夜,熬夜太多了,脑子要坏
xiaoming1992
2020-01-06 12:17:41 +08:00
@a132811 熬夜狗枯辣😭

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

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

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

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

© 2021 V2EX