惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AI
AI
WordPress大学
WordPress大学
博客园 - 聂微东
Hugging Face - Blog
Hugging Face - Blog
小众软件
小众软件
V
V2EX
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
V
Visual Studio Blog
The GitHub Blog
The GitHub Blog
IT之家
IT之家
D
Docker
M
MIT News - Artificial intelligence
D
DataBreaches.Net
博客园 - 三生石上(FineUI控件)
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
博客园_首页
Y
Y Combinator Blog
F
Full Disclosure
Microsoft Security Blog
Microsoft Security Blog
月光博客
月光博客
C
CXSECURITY Database RSS Feed - CXSecurity.com
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Spread Privacy
Spread Privacy
Know Your Adversary
Know Your Adversary
A
Arctic Wolf
Vercel News
Vercel News
T
Threat Research - Cisco Blogs
T
Threatpost
Apple Machine Learning Research
Apple Machine Learning Research
L
LINUX DO - 热门话题
T
The Exploit Database - CXSecurity.com
N
Netflix TechBlog - Medium
GbyAI
GbyAI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
Tailwind CSS Blog
J
Java Code Geeks
爱范儿
爱范儿
Cisco Talos Blog
Cisco Talos Blog
博客园 - 叶小钗
Latest news
Latest news
C
Check Point Blog
阮一峰的网络日志
阮一峰的网络日志
博客园 - Franky
P
Privacy International News Feed
MyScale Blog
MyScale Blog
Project Zero
Project Zero
Simon Willison's Weblog
Simon Willison's Weblog

TypeScript

ts 生态有没有开源的简单的 kv 配置管理项目 - V2EX 你们是怎么学习 typescript 的? - V2EX 用 Go 移植的 TypeScript 7 要来了 - V2EX TypeScript5.9,仿佛走出草原来到了现代社会 - V2EX Typescript 有没有能对接 AI 的知识库或者文档?能处理稍微复杂点的类型 - V2EX typescript 如何返回一个动态对象类型 - V2EX ts 有没有直接能查看最终类型的方法 - V2EX TypeScript Native 预览版发布了 - V2EX 关于 TypeScript 装饰器和接口的问题,请教一下各位 - V2EX 你们 typescript 用自带枚举还是字符串枚举,感觉字符串枚举类型用起来有点不可靠啊 - V2EX effect-ts - V2EX typescript 达人乱入 - V2EX TypeScript 宣布原生移植计划,性能将提升 10 倍? - V2EX #笔记#更好的 ts 重载声明方法 - V2EX 使用 satisfies 实现穷举类型保护 - V2EX 请教一个 TS 问题,不知能否实现 - V2EX 装饰器能不能装饰类的所有方法 - V2EX TypeSciprt 类型推断,如何进一步收窄类型? - V2EX TypeScript 项目打包发布到 npm,如何给方法和接口添加 dts TypeScript 类型推导真强大。 - V2EX 为啥下面这段代码 TS 不报错 - V2EX ts 类型约束+请求参数校验+自动生成 openapi/swagger 文档,这三者目前有整合为一体的最佳实践吗 - V2EX TypeScript 能不能别这么古怪,这行为什么会报错呢? - V2EX 怎么每次碰到想不通的代码行都出在 TypeScript😢 这行到底哪里有问题? - V2EX 低估了 typescript 的难度 - V2EX 前端写 nestjs 后端,用 TypeORM 时感到非常困惑,不知道是不是我的理解有问题 - V2EX 我列举了市面上最好的几个 TypeScript 教程, 想深入学习 TypeScript 的同学以后不用走弯路了 - V2EX 这样的函数类型定义在 ts 里面叫什么? - V2EX typescript 如何忽略泛型参数啊? - V2EX TypeScript 现在的应用场景 - V2EX ==TypeScript 写的 npm 包可以用 javascript 使用包的函数吗 - V2EX react 如何优雅的实现批量删除+二次确认 - V2EX TypeScript 怎么 wrap 一个函数并修改一下返回值? - V2EX 想请教个 TypeScript 抽象类继承父类的问题。 - V2EX vscode 纯 js 项目有类型推断和成员变量提示,但是如果 ts 混用的话, js 导入就全变成 any 了,请问有办法解决吗 这个项目这样定义 Typescript 类型和使用,学到了,有几个问题? - V2EX 请教一个 Typescript 的问题 - V2EX 这种的类型是不是实现不了(TypeScript) - V2EX 问题一个 typescript 类型包裹问题 - V2EX 遇到了极其诡异的不符合进入 if 条件的要求但是还是进入了 - V2EX typescript 的类型处理 - V2EX 想问问大家 TypeScript 中关于 null 处理的方式 - V2EX 有没有声明 typescript 类型的好办法以及前端样式的健壮性问题 - V2EX typescript 类型断言问题 - V2EX TypeScript 中类型编程简介 - V2EX [求助] 类型 { K:V } --> { "type": K , "conf": V } 且约束 - V2EX 大佬们, vscode 开发 ts,这个地方的提示,怎么修改成中文啊 - V2EX TypeScript 中「类型定义的命名空间」使用 - V2EX 有没有办法把 ts 的 error 报错改成 warning - V2EX
[求助] 函数中使用泛型缩小参数类型 - V2EX
lqzhgood · 2023-09-06 · via TypeScript

这是一个创建于 1013 天前的主题,其中的信息可能已经有所发展或是发生改变。

我有一个 Map ,一一对应。

TAP_TYPE.LOCAL 对应 TAP_LOCAL,

TAP_TYPE.MAP 对应 TAP_MAP

我在函数中已经通过 switch 约束 test 的 v, 为什么 ts 还是推导 v 的类型是 TAP_LOCAL | TAP_MAP

或者对这样的例子,除了对 v 进行强制断言,有什么更好的写法吗?

enum TAP_TYPE {
    'LOCAL',
    'MAP',
}

interface TAP_LOCAL {
    a: string;
}

interface TAP_MAP {
    b: string;
}

type TapTypeMap = {
    [TAP_TYPE.LOCAL]: TAP_LOCAL;
    [TAP_TYPE.MAP]: TAP_MAP;
};

function test<T extends TAP_TYPE>(t: T, v: TapTypeMap[T]) {
    switch (t) {
        case TAP_TYPE.LOCAL:
            return v.a;  // 类型错误  类型“TAP_LOCAL | TAP_MAP”上不存在属性“a”。
        case TAP_TYPE.MAP:
            return v.b;  // 类型错误  类型“TAP_LOCAL | TAP_MAP”上不存在属性“b”。
    }
}
Opportunity

1

Opportunity      2023 年 9 月 7 日

当 T=TAP_TYPE 有 t: TAP_TYPE, v: TAP_LOCAL | TAP_MAP 。
此时,t 和 v 没有任何关系,你对 t 再怎么判断也不应当影响 v 的类型,我觉得 ts 的推断没有任何问题。

我觉得断言已经是最好的方案了,接口上你可以选择使用重载代替泛型,避免 T=TAP_TYPE 这种情况,实现没啥好办法。

lqzhgood

2

lqzhgood      2023 年 9 月 7 日

@Opportunity #1
我理解给参数 v TapTypeMap[T] 类型就是让 ts 知道 “一一对应的关系”

switch 外层的 v 类型是 TAP_LOCAL | TAP_MAP 没错
但是通过 switch 缩小 t 的范围,关联到 TapTypeMap[T] 从而缩小 v 的范围我觉得也没问题吧~

后来我想通过函数重载的方式去实现也一样报错了~

```ts
function test(t: TAP_TYPE.LOCAL, v: TAP_LOCAL);
function test(t: TAP_TYPE.MAP, v: TAP_MAP);
function test(t: TAP_TYPE, v: TAP_LOCAL | TAP_MAP) {
switch (t) {
case TAP_TYPE.LOCAL:
return v.a; //报错
case TAP_TYPE.MAP:
return v.b; //报错
}
}
```

顺着重载的思路搜到这个 2020 年的帖子 https://www.zhihu.com/question/402139008
问题类似,也没解决~

Opportunity

3

Opportunity      2023 年 9 月 8 日   ❤️ 1

我的意思是,调用方这样写:
```
const t: TAP_TYPE = TAP_TYPE.LOCAL
test(t, {b:'xx'})
```
TS 不会报任何错误,运行时会炸。用函数重载可以在运行时就报错。

如果你硬要把接口搞成这样,就要想办法告诉 TS 两个参数的联系,比如这样写:

```
function test(...[t, v]: [t: TAP_TYPE.LOCAL, v: TAP_LOCAL] | [t: TAP_TYPE.MAP, v: TAP_MAP]) {
switch (t) {
case TAP_TYPE.LOCAL:
return v.a;
case TAP_TYPE.MAP:
return v.b;
}
}
```
但是说实话,太丑了,我更倾向于用 as

chnwillliu

5

chnwillliu      2023 年 9 月 11 日   ❤️ 1

1. switch (t) 缩窄的是变量 t 的类型,并不会影响泛型 T 的范围,就算 T 真能跟随 case 缩窄变化,v:TapTypeMap[T] 也不能获得联动缩窄。T 是一个未知类型,extends 只是约束了这个未知的边界。
2. t 的类型是 TAP_TYPE 的子类型,导致 case 对 t 的类型缩窄失效,此时 t 的类型不再是可缩窄类型。TAP_TYPE 是 enum 类型,类似 union type ,可以缩窄,但从 enum 派生出去的类型不一定可缩窄。

enum TAP_TYPE {
LOCAL,
MAP,
}

interface TAP_LOCAL {
a: string;
}

interface TAP_MAP {
b: string;
}

type TapTypeMap = {
[TAP_TYPE.LOCAL]: TAP_LOCAL;
[TAP_TYPE.MAP]: TAP_MAP;
};

function test<T extends TAP_TYPE>(t: T, v: TapTypeMap[T]): string;
function test(t: TAP_TYPE, v: TapTypeMap[TAP_TYPE]): string {
switch (t) {
case TAP_TYPE.LOCAL:
return (v as TapTypeMap[typeof t]).a;
case TAP_TYPE.MAP:
return (v as TapTypeMap[typeof t]).b;
}
}

chnwillliu

6

chnwillliu      2023 年 9 月 11 日

#3 借助元组进行联动缩窄的方法很巧妙。

lqzhgood

7

lqzhgood      2023 年 9 月 12 日

@chnwillliu #5

我不太明白第二点~
请教第二点的意思是 `t extends TAP_TYPE` !== `t: TAP_TYPE` 么?
对于 TAP_TYPE 是一个 enum 类型的情况下,上述应该是相等的吧? 我好像找不出反例

chnwillliu

8

chnwillliu      2023 年 9 月 12 日 via Android

@lqzhgood

这里就要说到 ts 的 nominal type checking.

type foo = 0 & {brand: 'foo'}

这里 foo 并不会是 never ,这是 ts 刻意为之的,虽然运行时不可能存在一种值满足这个类型。(但是可以在 ts 层面 as 啊)

type bar = (0 & {brand: 'foo'}) extends 0 ? true : false; // true

function test<T extends TAP_TYPE>(t: T, v: TapTypeMap[T])

T 实际有可能是 TAP_TYPE.LOCAL & {a:1} 或与任意其他 interface 的交叉类型。