TypeScript begränsar antalet egenskaper på ett objekt


Är det möjligt att begränsa antalet egenskaper i ett objekt, till exempel vill jag begränsa att ett objekt endast har en strängegenskap (med vilket namn som helst), jag kan göra:

{[index: string]: any}

att begränsa typen av egendom, men kan man också begränsa antalet egendomar?

Svar #1

Det finns många svar på denna fråga på Stackoverflow (inklusive detta detaljerade), men inget av dem fungerade för min situation, som är lik den som publicerats här.

Problem

Jag har en funktion som tar ett objekt. Jag vill att den ska kasta ett kompilationsfel (Typescript) om det passerade objektet inte har exakt en nyckel. t.ex.

f({}); // Must error here, as it has less than one key!
f({ x: 5 });
f({ x: 5, y : 6 }); // Must error here, as it has more than one key!

Lösning

Med hjälp av de populära UnionToIntersection och IsUnion, uppnådde jag det via följande hjälpmetod.

type SingleKey<T> = IsUnion<keyof T> extends true ? never : {} extends T ? never : T;

Fullständig kod:

// From https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;

// From: https://stackoverflow.com/a/53955431
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;

// Here we come!
type SingleKey<T> = IsUnion<keyof T> extends true ? never : {} extends T ? never : T;

// Usage:
function f<T extends Record<string, any>>(obj: SingleKey<T>) {
    console.log({ obj });
}

f({}); // errors here!
f({ x: 5 });
f({ x: 5, y : 6 }); // errors here!

Lekplatslänk

Svar #2

Troligtvis inte. Den bästa lösningen som kommer till mig är att omsluta ett Object (eller Map) med din egen klass med metoderna set(key: string, val: any) och get(key: string) som kan förhindra att nya objekt läggs till i den underliggande samlingen under vissa omständigheter.

Relaterade artiklar