typescript - Rozšíriť `Record` o vlastnosť iného typu
V TypeScripte sa zdá, že nasledujúce by malo zabezpečiť vytvorenie požadovaného typu:
interface RecordX extends Record<string, string[]> {
id: string
}
ale toto sa sťažuje na:
Vlastnosť 'id' typu 'string' nie je priraditeľná k typu indexu reťazca 'string[]'. ts(2411)
Ako možno pridať vlastnosť iného typu k utilitnému typu Record<>?
Detaily a všeobecný prípad + ukážka
Všeobecne, ako by sa dal opísať objekt s fixnými vlastnosťami rôznych typov hodnôt, ale s vlastnosťami rovnakého typu hodnôt, ktoré sa pridávajú dynamicky.
S, napríklad daný tento objekt:
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
Ako teda možno definovať typ alebo rozhranie ExtensibleRecord, kde:
- typy a kľúče vlastností
id,countasetsú pevne dané akostring,numberaSet<number> - typy
dynamicItemListaanotherDynamicallyAddedLista všetky ďalšie vlastnosti pridané do objektu sústring[]
Skúšal som mnoho variantov, o ktorých by som si myslel, že by mohli fungovať, vrátane:
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[]
}
ale každý sa zdá viesť k chybám.
Toto pôsobí ako niečo bežné a zrejmé, ale nemôžem nájsť príklad alebo odkaz.
detské ihrisko
Odpoveď č. 1
Z oficiálnej dokumentácie nie je možné dosiahnuť to, čo chcete:
Hoci indexové podpisy reťazcov sú silným spôsobom, ako popísať vzor „slovníka“, tiež vynucujú, aby všetky vlastnosti zodpovedali svojmu návratovému typu. Je to preto, že index reťazcov deklaruje, že obj.property je tiež dostupné ako obj["property"]. V nasledujúcom príklade typ premennej name nezodpovedá typu indexu reťazca a kontrolór typov zobrazí chybu:
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 }
Avšak podľa tohto webu je možné vylúčiť niektoré vlastnosti z indexového podpisu v jednej situácii: keď chcete modelovať deklarovanú premennú. Kopírujem celý úsek zo stránky.
Niekedy je potrebné kombinovať vlastnosti do podpisu indexu. Toto sa neodporúča a mali by ste použiť vzor vnoreného podpisu indexu, ktorý je uvedený vyššie. Ak však modelujete existujúci JavaScript, môžete sa tomu vyhnúť pomocou typu prieniku. Nasledujúci príklad ukazuje chybu, na ktorú natrafíte bez použitia typu prieniku:
type FieldState = { value: string } type FormState = { isValid: boolean // Error: Does not conform to the index signature [fieldName: string]: FieldState }Tu je obchádzka pomocou priesečníkového typu:
type FieldState = { value: string } type FormState = { isValid: boolean } & { [fieldName: string]: FieldState }Všimnite si, že aj keď ho môžete deklarovať, aby modeloval existujúci JavaScript, nemôžete vytvoriť takýto objekt pomocou TypeScriptu:
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 }
Nakoniec, ako obchádzku, ak to sedí, môžete vytvoriť vnorené rozhranie (skontrolujte sekciu „Dizajnový vzor: Vnorený indexový podpis“ na stránke, v ktorom sú dynamické polia v vlastnosti rozhrania. Napríklad
interface RecordX {
id: string,
count: number,
set: Set<number>,
dynamicFields: {
[k: string]: string[]
}
}
Odpoveď č. 2
Ak to nepoužívate pre class, môžete to popísať pomocou type:
type RecordWithID = Record<string, string[]> & {
id: string
}
let x: RecordWithID = {} as any
x.id = 'abc'
x.abc = ['some-string']
http://www.typescriptlang.org/play/#code/C4TwDgpgBAShDGB7ATgEwOoEtgAsCSAIlALywIqoA8AzsMpgHYDmANFLfcwNoC6AfFABkUAN4BYAFBQomVAC52dRk0kBfSZIA2EYFAAeCuEjRZchEqNVQAhtRsMQGiXoB0siwHJrAI3genrj7wFlxe1KgAZh48TkA
