卧槽了 TypeScript 真不是一般人能完全驾驭的,太微妙了,这里的写法搞不懂有什么不对的

2021-10-17 12:44:48 +08:00
 makelove

写了一个复杂的函数定义,怎么搞里面的类型都是 unknown,我把问题部分最简化成这样:

Playground 链接

declare function create<A>(def: {
  a: () => A
  b: (a: A) => void
}): A

let s = create({
    a: () => { return { result: () => 'ok' } },
    b: (a) => {},
})

let s2 = create({
    a: () => { return { result() { return 'ok' } } },
    b: (a) => {},
})

你看这个 s 和 s2 定义是几乎一样的吧,一个出来是正常的类型 { result: () => "ok"; } 另一个是unknown。 谁知道这里到底有什么微妙的东西的里面?

js 怎么搞就这么点东西没有不明明白白的,ts 有时候真抓狂。

6376 次点击
所在节点    TypeScript
46 条回复
akinoniku
2021-10-17 12:54:26 +08:00
s 和 s2 在 js 不是等价的
makelove
2021-10-17 13:01:18 +08:00
@akinoniku 是,就差了个 this 处理。
我这里需要传入一个函数集,所以我这里只能写个注解让别人传入函数集时要用 => 写法不能用另一种?这有点太搞笑了
codehz
2021-10-17 13:12:35 +08:00
s2 改成这样

let s2 = create({
a: () => { return { result() { return 'ok' } } as const },
b: (a) => {},
})
makelove
2021-10-17 13:17:39 +08:00
@codehz 为何 s2 加 const 就可以了呢,和 s 可以不加差在哪呢
hronro
2021-10-17 13:18:47 +08:00
感觉有点像是 TypeScript 本身的 BUG,建议你去 TypeScript 报个 issue
makelove
2021-10-17 13:31:40 +08:00
@hronro 这就不给别人添乱了,这个不可能会是未知 BUG,这么常用的东西即使是 BUG 也有大把人在提了,毕竟 ts 这流行度摆在那
gynantim
2021-10-17 13:47:13 +08:00
不是 bug 吧。因为 s 能够通过静态分析得到类型。s2 不能。
hronro
2021-10-17 13:58:56 +08:00
@makelove #6
我好心帮你看问题,为什么说我添堵?

如果一个 Object literal 直接申明能推断出类型,inline 到某个对象里就不能推断出类型,这为什么不可能是 TS 的 BUG?

makelove
2021-10-17 14:00:58 +08:00
@gynantim 请问:

declare function create<S, M, A>(def: {
data: S
a: (data: S) => M
b: (m: M) => void
}): M

const s = create({
data: 0,
a: (data) => 100,
b: (m) => {}
})


这种情况,为何 s 也是 unknown 呢
感觉这是 ts 的某种特点,不过不知道在哪能有说明
makelove
2021-10-17 14:06:25 +08:00
@hronro 怎么说呢,我不是说这不一定不是个 bug,而是说即使是 bug typescript 的 issue 列表里也肯定有了。(以前我初学 ts 时就提过几个百思不得其解的 bug,后来发现都是别人提烂的,typescript 几万个 issue 不是盖的,你能想到的几乎都有,我想不是资深 ts 人士提不出新 bug
包括这个,因为不好找关键词所以我没找到相关 bug
xarthur
2021-10-17 14:13:42 +08:00
首先 S1 和 S2 **应该**返回的类型是不一样的。
S1 返回的是 { result: () => string; },是个对象,里面有个 result 的属性,这个属性的类型是 () => string
S2 返回的是 { result() : string },是个对象,这个对象里有个 result() 的方法,这个方法的返回值应该是 string
但是在你的写法中你是没法判断{ return { result() { return 'ok' } } }这句话是要返回一个对象还是一个 闭包 /代码块 的,类型推断只能出 unknown 。
我是这么理解的。
xarthur
2021-10-17 14:17:28 +08:00
如果你要写一个方法集合的话,应该用第一种写法,第二种写法是错的。
makelove
2021-10-17 14:17:38 +08:00
@xarthur 应该不是这个问题,这个很明显是对象。
你看我最后回复给 gynantim 里,那里没有对象了是个数字,结果也是 unknown
xarthur
2021-10-17 14:22:37 +08:00
@makelove 第二个例子确实很奇怪,100 应该会自动推断成 number🤔
hronro
2021-10-17 14:28:36 +08:00
@makelove #10
所以我才建议在 issue 列表里搜不到就直接去开新 issue,如果之前真的有人提过但你没搜到,会有人帮你标 duplicated 的。我过去几年给 TS 提过几个 issue,确实有一半是 duplicated 的,不过另外一半是确实是 TS 本身的问题
xarthur
2021-10-17 14:34:00 +08:00
@makelove 我现在倾向于 TS 出于某种可能会出现递归类型推断计算的可能性,直接暂停了这部分的类型推断,所以出现了 unknown 。
也或许这个是 TS 的 bug
lvdb
2021-10-17 14:34:53 +08:00
@xarthur 第二个例子,你 b 在 declare 的时候返回值是 void,但是你调用的时候 b 的返回值类型是{},这代表一个空对象,并不是 void 。所以 ts 这时候不能推断出 s 是什么类型。。。
lvdb
2021-10-17 14:35:24 +08:00
@lvdb 抱歉回复错了。。 @xarthur @makelove
makelove
2021-10-17 14:39:26 +08:00
@lvdb 不是,js 语法这里的空{}不是返回空对象而是不返回东西,实际返回就是 void,或者你在里面写 return undefined as void 也是一个效果
lvdb
2021-10-17 14:58:13 +08:00
@makelove 建议你在 playground 里 console.log(typeof {}),看一下 log

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

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

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

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

© 2021 V2EX