javascript - Hur använder man konstruktörer som objekt nycklar?
Jag försöker konstruera en karta över typer och callbacks, så jag började med en struktur som den här:
type Instantiable<T = unknown> = new (...args: any[]) => T;
type SingleParamFn<TInput = unknown, TOuput = unknown> = (arg: TInput) => TOuput;
type TypesRecord<T> = { type: Instantiable<T>, callback: SingleParamFn<T> };
type TypesMap = TypesRecord[]; // This is the structure
Ett exempel på detta:
const myMap: TypesMap = [{ type: Date, callback: (value) => 'this is a Date' }];
Detta verkar fungera som förväntat, men jag insåg att det är lite ineffektivt eftersom du måste loopa igenom arrayen för att hitta den typ du vill ha.
Jag började leka med att ha typerna som objektnycklar och det verkar fungera åtminstone i Google Chrome:
class MyFancyObject {}
class MyOtherObject {}
const map = {
[Date]: () => 'this is a date',
[MyFancyObject]: () => 'this is a fancy object',
[MyOtherObject]: () => 'this is another object'
};
console.log(map[Date]()); // 'this is a date'
console.log(map[MyFancyObject]()); // 'this is a fancy object'
console.log(map[MyOtherObject]()); // 'this is another object'
const obj = new MyFancyObject();
console.log(map[obj.constructor]()); // 'this is a fancy object'
console.log(map[(new Date()).constructor]()); // 'this is a date'
Jag har gått igenom viss dokumentation och det verkar som att en objektsnyckel bara kan vara en sträng eller en Symbol, så jag kollade vad som utgör en Symbol och det verkar vara lite vagt eftersom den definieras som ett inbyggt objekt vars konstruktör returnerar ett symbol-primitiv som garanterat är unikt och ett objekts konstruktör är (så vitt jag vet) unik.
Med tanke på allt detta, är det pålitligt att använda konstruktörerna som objektnycklar? Om så är fallet, hur kan jag definiera TypeScript-typen för ett sådant objekt? Om det inte är det, finns det andra alternativ (som Map-objektet)?
Svar #1
Med tanke på allt detta, är det pålitligt att använda konstruktörer som objektnycklar?
Nej. Som du sa kan ett objekts nycklar bara vara strängar eller Symboler. En Symbol är ett primitivt värde som du får från en egenskap på Symbol (för väletablerade, specifikationsdefinierade Symboler) eller genom att anropa Symbol() eller Symbol.for("..."). Konstruktionsfunktioner är inte symboler, de är funktioner.
Nycklarna i ditt map-objekt är strängar. När du använder ett beräknat egenskapsnamn som [MyFancyObject], om värdet du anger inte är en sträng eller en Symbol (i ditt fall är det en funktion), konverteras det implicit till en sträng som om du gjorde String(MyFancyObject). Du kan se det här:
class MyFancyObject {}
class MyOtherObject {}
const map = {
[Date]: () => 'this is a date',
[MyFancyObject]: () => 'this is a fancy object',
[MyOtherObject]: () => 'this is another object'
};
console.log(Object.keys(map));
console.log(map[MyFancyObject]()); // "this is a fancy object"
console.log(map["class MyFancyObject {}"]()); // also "this is a fancy object"Som du kan se, nyckeln du tänker på som MyFancyObject är faktiskt strängen "class MyFancyObject {}".
Du kan använda konstruktörsfunktioner som nycklar i en Map, dock:
class MyFancyObject {}
class MyOtherObject {}
const map = new Map([
[Date, () => 'this is a date'],
[MyFancyObject, () => 'this is a fancy object'],
[MyOtherObject, () => 'this is another object'],
]);
console.log(map.get(MyFancyObject)());I det avseendet är nycklarna verkligen konstruktionsfunktionerna, inte strängar härledda från dem.
