3 votes

Pourquoi typescript ne peut pas déduire le type de `T[clé de T]` pour le paramètre de type `T` ici ?

J'essaie d'écrire une classe générique à qui l'on passe une clé key correspondant à une clé d'une interface parmi un ensemble d'interfaces connues lors de la construction et à qui on peut ensuite passer un objet thing et accéder en toute sécurité à thing[key] . C'est ce que j'ai :

interface AB {
  a: string
  b: number
}

interface BC {
  b: number
  c: Date
}

type ABC = AB | BC

class Getter<T extends ABC> {
  key: keyof T;

  constructor(key: keyof T) {
    this.key = key;
  }

  get(thing: T): string {
    const value = thing[this.key];
    return value.toString();
  }

}

const getter = new Getter<AB>('b');

Lien vers le terrain de jeux

Ici, je m'attendrais à ce que Typescript déduise que parce que T extends ABC que T[keyof T] = AB[keyof AB] | BC [keyof BC] = string | number | date . Cependant, il semble rester bloqué à T[keyof T] . Même en ajoutant un as AB[keyof AB] | BC[keyof BC] à cette ligne n'arrange pas les choses, j'ai besoin as unknown as AB[keyof AB] | BC[keyof BC] ! Y a-t-il un moyen de faire fonctionner ce système sans cette ligne ?

De plus, existe-t-il un moyen de paramétrer la valeur de l'option key comme un type au lieu de paramétrer sur le type de thing ?

1voto

ghybs Points 21950

Quand T extends ABC il peut avoir de nombreuses autres propriétés et types. Qui ne peut donc pas avoir .toString() méthode.

type G = {
  a: string;
  b: number;
  hello: undefined;
};

const g = new Getter<G, keyof G>("hello");

g.get({
  a: "a",
  b: 1,
  hello: undefined
}); // undefined does not have .toString() method

Lien vers le terrain de jeux

1voto

Bergi Points 104242

Existe-t-il un moyen de paramétrer la valeur de la clé en tant que type au lieu de paramétrer le type de la chose ?

Oui, rien de plus facile que ça :

class Getter<Key extends string | symbol> {
  key: Key;

  constructor(key: Key) {
    this.key = key;
  }

  get(thing: {[k in Key]: string | number | Date}): string {
    const value = thing[this.key];
    return value.toString();
  }
}

( Démonstration du terrain de jeu )

0voto

Il s'agit simplement d'une limitation de la nature du script. Vous devez vérifier les membres, puis effectuer un cast typé au moment de l'exécution. J'espère que cela vous aidera !

Par exemple :

if (AnimalObject.Object.Keys().Includes('Name')) {
  // We now know the generic type has a matching member
}

En ce qui concerne l'implémentation, je ferais une liste des interfaces que 'T' peut être, puis un tableau de membres pour chaque interface, en suivant la logique ci-dessus, vous pouvez obtenir quelque chose comme :

// Store your valid types for checking
const ValidInterfacesSet: any[] = {Dog,Cat,car,Mammal};

//Look through members and confirm them... 
GetAndCastType(typeToCheck: any) {
    typeToCheckKeys: string = typeToCheck.Object.keys();
    for (inter: any of ValidInterfacesSet) {
        const interMemberNames: string[] = inter.object.keys();

        if(array1.sort().join(',')=== array2.sort().join(',')) {
          // Returning the casted type if the iter members contain the same as typeToCheckMembers
             return typeToCheck as inter; 
        }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X