带有 toString() 的类可以用作字符串,但是如何说服 TypeScript 编译器呢?

Posted

技术标签:

【中文标题】带有 toString() 的类可以用作字符串,但是如何说服 TypeScript 编译器呢?【英文标题】:A class with toString() can be used as a string, but how to convince the TypeScript compiler? 【发布时间】:2021-09-15 02:03:45 【问题描述】:

我的类实现了toString() 以允许我在构建其他对象时方便地使用任何实例作为属性名称。 TypeScript 编译器虽然不相信并输出:a computed property name must be of type 'string' 如何以满足编译器的方式声明我的类?

class Foo 
  name: string  
  constructor(name: string)  this.name = name; 
  toString()  return this.name; 


可以这样使用:

const myFoo = new Foo('Clytemnestra');
const someObject =  [myFoo]: 'she murders Agamemnon';

目前上面的最后一行产生了上述类型错误。

【问题讨论】:

使用[myFoo.toString()]?鉴于几乎所有内容都可以强制转换为字符串,“尊重它会隐藏比启用有效模式更多的错误” per github.com/Microsoft/TypeScript/issues/14207。 使用静态类型系统的最大优势之一是避免了由您使用的确切类型的隐式转换所产生的问题。您必须明确转换。 乔恩和杰瑞德是对的。此外,您甚至没有在示例中包含有效的 Typescript。 ***.com/help/someone-answers 【参考方案1】:

你不能

您不能“说服”Typescript 静态类型检查器忽略对象的类型并依赖强制类型——这会破坏静态类型检查的全部目的。

但你可以...

0通过更改违规行来验证静态确定的类型:

const someObject =  [myFoo as unknown as string ]: 'she murders Agamemnon';

马上就臭了。

好的,怎么样:

const someObject =  [ myFoo.toString() ]: 'she murders Agamemnon';

这稍微好一些,因为您明确地对字符串进行“强制”。

但这两个最终都是一个坏主意。任何对象都可以强制转换为字符串,默认值通常是“[object Object]”。依赖toString() 方法会破坏类型安全。因此,您再次违背了静态类型检查的目的。你一定要问:我为什么要使用 Typescript?

相反,一种更安全的方法

class Subject 
  name: string
  city: string
  constructor(name: string, city: string)  
    this.name = name
    this.city = city
  


const vengefulWife = new Subject('Clytemnestra', 'Mycenae');

const summaries = new Map<Subject, string>()
summaries.set(vengefulWife, 'she murders Agamemnon')


for (const [key, value] of summaries) 
  console.log(`$key.name of $key.city: $value`);


因为 Typescript 知道 key 的类型,所以它可以识别 对key.namekey.city 的引用是有效的

【讨论】:

以上是关于带有 toString() 的类可以用作字符串,但是如何说服 TypeScript 编译器呢?的主要内容,如果未能解决你的问题,请参考以下文章

toString方法分析

从用作数据部分的字符串派生的类

Java中啥时候需要显示重载toString方法

具有委托属性的类的toString重写限制

Java之toString方法

如何初始化用作函数参数的类类型