判断以下代码:

interface B<T> {
  bla?: T;
}

class A implements B<string> {
}

type thisShouldBeString = A extends B<infer T> ? T : never;

我想从A中推断出字符串,这可能吗?多么?

伊迪丝:这是我的另一个方法,但没有奏效:

interface B<T> {
  bla?: T;
}

class A implements B<string> {
}

type thisShouldBeString = A extends { bla?: infer T } ? T : never;

推荐答案

值得注意的是,这an implements clause doesn't actually affect the type of the class to which it's applied个.类只遵守已实现的类型的check,除此之外,判断所有内容的行为就像没有子句一样.因此,当涉及到类型推断时,

class A implements B<string> { }

完全相同于

class A { }

这意味着A就是an empty class,你可以期待奇怪的事情发生.

特别是,当您try 使用conditional type inferenceinferT,其中A extends B<T>,它将不会像预期的那样工作.如果B<T>的子类型没有bla属性,则Tunused,这是prevents inference.A可赋值给B<T> for any possible 104.编译器没有理由优先 Select string而不是任何其他类型,因此推理失败,并回退到the unknown type:

type ThisShouldBeString = A extends B<infer T> ? T : never;
//type ThisShouldBeString = unknown ?

为了使这可能起作用,您需要确保AB<T>之间的比较是100 dependenceT.例如:

class A /* implements B<string> */ {
  declare bla?: string;
}

现在A有一个 struct ,可以有意义地将其与B<T>进行比较,即使没有implements从句(同样,这不会影响事情).推论成功了:

type ThisShouldBeString = A extends B<infer T> ? T : never;
//type ThisShouldBeString = string ?

万岁!

顺便说一句,这与作为JavaScript发出的A版本没有任何关系.假设我有declaredbla属性,它甚至不会在运行时出现.A的两个版本都将编译成类似class A {}的版本.它们之间的区别只是在静态类型系统上.

Playground link to code

Typescript相关问答推荐

自定义挂钩上的React useState正在忽略提供的初始状态

之间是否有区别:例如useEffect()React.useEffect()

为什么在TypScript中将类型守护的返回类型写成This is(

Typescript对每个属性具有约束的通用类型

ReturnType此索引方法与点表示法之间的差异

如何从TypScript中的接口中正确获取特定键类型的所有属性?

对数组或REST参数中的多个函数的S参数进行类型判断

在不更改类型签名的情况下在数组并集上映射文字

通过字符串索引访问对象';S的值时出现文字脚本错误

如何在已知基类的任何子类上使用`extends`?

找不到财产的标准方式?

基元类型按引用传递的解决方法

我在Angular 17中的environment.ts文件中得到了一个属性端点错误

打字错误TS2305:模块常量没有导出的成员

如何在具有嵌套数组的接口中允许新属性

类型脚本中函数重载中的类型推断问题

仅当定义了值时才按值筛选数组

两个接口的TypeScript并集,其中一个是可选的

Typescript 和 Rust 中跨平台的位移数字不一致

Typescript 确保通用对象不包含属性