在 Typescript 中,以下内容似乎应该完成所需类型的创建:
interface RecordX extends Record<string, string[]> {
id: string
}
Run Code Online (Sandbox Code Playgroud)
但这抱怨:
“string”类型的属性“id”不可分配给字符串索引类型“string[]”。ts(2411)
如何将不同类型的属性添加到Record<>实用程序类型?
通常,如何描述具有异构值类型固定属性但动态添加同质值类型属性的对象。
S,例如给定这个对象:
const a = {
// some properties with known "hard-coded" types
id: '123',
count: 123,
set: new Set<number>(),
// and some dynamic properties
dynamicItemList: ['X', 'Y']
anotherDynamicallyAddedList: ['Y', 'Z']
} as ExtensibleRecord
Run Code Online (Sandbox Code Playgroud)
那么如何定义类型或接口ExtensibleRecord,其中:
id,count和set被固定为string,number和Set<number>dynamicItemList和anotherDynamicallyAddedList和任何其他属性的类型是string[]我尝试了许多我认为可能有效的变体,包括:
type ExtensibleRecord = {
id: string, count: number, set: Set<number>
} & Record<string, string[]>
type ExtensibleRecord = {
id: string, count: number, set: Set<Number>
} & Omit<Record<string, string[]>, 'id'|'count'|'set'>
interface ExtensibleRecord = {
id: string,
count: number,
set: Set<number>,
[k: string]: string[]
}
Run Code Online (Sandbox Code Playgroud)
但每个似乎都会导致错误。
这感觉像是常见且显而易见的事情,但我找不到示例或参考。
从官方文档中,不可能实现您想要的:
虽然字符串索引签名是一种描述“字典”模式的强大方式,但它们也强制所有属性匹配它们的返回类型。这是因为字符串索引声明 obj.property 也可用作 obj["property"]。在下面的例子中,name 的类型与字符串索引的类型不匹配,类型检查器给出了一个错误:
Run Code Online (Sandbox Code Playgroud)interface NumberDictionary { [index: string]: number; length: number; // ok, length is a number name: string; // error, the type of 'name' is not a subtype of the indexer }
但是,根据此站点,在一种情况下可以从索引签名中排除某些属性:当您想要对声明的变量进行建模时。我正在从网站复制整个部分。
有时您需要将属性组合到索引签名中。不建议这样做,您应该使用上面提到的嵌套索引签名模式。但是,如果您正在对现有 JavaScript 进行建模,则可以使用交集类型绕过它。下面显示了不使用交集时会遇到的错误示例:
Run Code Online (Sandbox Code Playgroud)type FieldState = { value: string } type FormState = { isValid: boolean // Error: Does not conform to the index signature [fieldName: string]: FieldState }这是使用交集类型的解决方法:
Run Code Online (Sandbox Code Playgroud)type FieldState = { value: string } type FormState = { isValid: boolean } & { [fieldName: string]: FieldState }请注意,即使您可以声明它为现有 JavaScript 建模,也不能使用 TypeScript 创建这样的对象:
Run Code Online (Sandbox Code Playgroud)type FieldState = { value: string } type FormState = { isValid: boolean } & { [fieldName: string]: FieldState } // Use it for some JavaScript object you are gettting from somewhere declare const foo:FormState; const isValidBool = foo.isValid; const somethingFieldState = foo['something']; // Using it to create a TypeScript object will not work const bar: FormState = { // Error `isValid` not assignable to `FieldState isValid: false }
最后,作为一种解决方法,如果合适,您可以创建一个嵌套接口(检查site 的“设计模式:嵌套索引签名”部分,其中动态字段位于接口的属性中。例如
interface RecordX {
id: string,
count: number,
set: Set<number>,
dynamicFields: {
[k: string]: string[]
}
}
Run Code Online (Sandbox Code Playgroud)
如果您不将其用于class,则可以使用以下方式对其进行描述type:
type RecordWithID = Record<string, string[]> & {
id: string
}
let x: RecordWithID = {} as any
x.id = 'abc'
x.abc = ['some-string']
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4954 次 |
| 最近记录: |