javascript typescript中具有某种类型的任何属性的泛型类型

9lowa7mx  于 2023-04-04  发布在  Java
关注(0)|答案(1)|浏览(120)

大家好!😊

interface Thing {
  name: string;
}

interface ThingMap {
  [thingName: string]: Thing;
}

interface ThingMapClassA {
  first: { name: 'first thing name' };
  second: { name: 'second thing name' };
  third: { name: 'third thing name' };
}

interface ThingMapClassB {
  first: { name: 'first thing name' };
  second: { name: 'second thing name' };
  third: { name: 'third thing name' };
}

class Handler<T extends ThingMap> {}

const handler = new Handler<ThingMapClassA>();

我喜欢Handler接受任何具有Thing类型属性(理想情况下至少一个)的类。但是ThingMapClassA不被识别。这会导致错误。有什么建议吗?😊

qxgroojn

qxgroojn1#

类型

interface ThingMap {
  [thingName: string]: Thing;
}

具有字符串索引签名,这意味着如果该类型的对象具有键为string的属性,则该属性的值将为Thing
如果你有一个匿名对象类型,比如从对象字面量推断的类型,并试图将其分配给一个具有索引签名的类型,编译器将帮助它提供一个隐式索引签名:

const goodVal: ThingMap = { a: { name: "b" } }; // okay

const badVal: ThingMap = { a: "oops" }; // error
// ----------------------> ~
// Type 'string' is not assignable to type 'Thing'.
// The expected type comes from this index signature.

但是隐式索引签名 * 不 * 给予接口或class示例类型的值。这在microsoft/TypeScript#15300中描述。观察:

interface Iface {
  a: Thing;
}
const iface: Iface = { a: { name: "b" } };
const alsoBad: ThingMap = iface; // error!
// Index signature for type 'string' is missing in type 'Test'.

class Cls {
  a = { name: "abc" }
}
const cls: Cls = new Cls();
const alsoAlsoBad: ThingMap = cls; // error!
// Index signature for type 'string' is missing in type 'Cls'.

这就是你遇到的问题。ThingMapClassAThingMapClassB不能赋值给ThingMap,即使一个与之等价的匿名对象文字类型可以赋值给ThingMap。所以你需要改变你正在做的事情。
这里最简单的方法是将约束改为递归的。你只想知道它的属性可以赋值给Thing。这可以表示为

class Handler<T extends Record<keyof T, Thing>> { }

使用Record<K, V>实用程序类型。Record<keyof T, Thing>表示“与T具有相同键的对象,其属性的类型为Thing”。因此,如果T extends Record<keyof T, Thing>,则我们知道T的每个属性的类型为String
这就给了我们

const handler = new Handler<ThingMapClassA>(); // okay

const badHandler = new Handler<{ a: Thing, b: string }>(); // error!
// --------------------------> ~~~~~~~~~~~~~~~~~~~~~~~
// Types of property 'b' are incompatible.
// Type 'string' is not assignable to type 'Thing'

如所期望的。
Playground代码链接

相关问题