generiká - Môžete deklarovať typ objektového literálu, ktorý povoľuje neznáme vlastnosti v TypeScripte?
V podstate chcem zabezpečiť, aby argument objektu obsahoval všetky požadované vlastnosti, ale môže obsahovať aj akékoľvek ďalšie vlastnosti, ktoré bude chcieť. Napríklad:
function foo(bar: { baz: number }) : number {
return bar.baz;
}
foo({ baz: 1, other: 2 });
Ale toto vedie k:
Object literal may only specify known properties, and 'other' does not exist in type '{ baz: number; }'.
Odpoveď č. 1
Áno, môžeš. Skús toto:
interface IBaz {
baz: number;
[key: string]: any;
}
function foo(bar: IBaz) : number {
return bar.baz;
}
foo({ baz: 1, other: 2 });
Odpoveď č. 2
No, nenávidím odpovedať na svoje vlastné otázky, ale ostatné odpovede ma inšpirovali k malému zamysleniu... Toto funguje:
function foo<T extends { baz: number }>(bar: T): void {
console.log(bar.baz);
}
foo({baz: 1, other: 2});
Odpoveď č. 3
Ak známe polia pochádzajú z generického typu, spôsob, ako povoliť zástupné znaky, je s T & {[key: string]: unknown}, všetky známe polia musia vyhovovať obmedzeniam typu a ostatné polia sú povolené (a považované za typ unknown)
Tu je ukážka:
type WithWildcards<T> = T & { [key: string]: unknown };
function test(foo: WithWildcards<{baz: number}>) {}
test({ baz: 1 }); // works
test({ baz: 1, other: 4 }); // works
test({ baz: '', other: 4 }); // fails since baz isn't a number
Potom, ak máte generický typ T, môžete povoliť wildcard polia s WithWildCards<T>
Všimnite si, že extra vlastnosti nie sú označené ako chyby, ak objekt pochádza z niečoho iného než objektového literálu, TS vám len hovorí, že podľa typovania je pridanie tejto vlastnosti do literálu nadbytočné.
Tu sú niektoré ďalšie prípady, kde sú a nie sú povolené dodatočné vlastnosti
interface Foos{
a?: string
b?: string
}
type WithWildcards<T> = T & { [key: string]: unknown };
declare function acceptFoos(foo: Foos): void;
declare function acceptWild(foo: WithWildcards<Foos>):void
acceptFoos( {a:'', other: ''}) // ERROR since the property is extraneous
const data = {a:'', other: ''}
acceptFoos( data) // allowed since it is compatible, typescript doesn't force you to remove the properties
const notCompat = {other: ''}
acceptFoos(notCompat) //ERROR: Type '{ other: string; }' has no properties in common with type 'Foos'
acceptFoos({a:'', ...notCompat}) // this is also allowed
acceptWild(notCompat) // allowed
Odpoveď č. 4
Ak chcete povoliť neznáme vlastnosti pre celý objekt, môžete použiť Record
function doStuff(payload: Record<string|number, unknown>): Record<string|number, unknown> {
return { anyProp: 'anyValue' }
}
