5 votes

Typescript - étendre progressivement le type d'un objet

J'essaie d'obtenir les résultats suivants avec TS :

let m: Extendable
m.add('one', 1)
// m now has '.one' field
m.add('two', 2)
// 'm' now has '.one' and '.two' fields

J'ai l'habitude de renvoyer des types étendus dans TS via :

function extend<T, V>(obj: T, val: V): T & {extra: V} {
    return {
        ...obj,
        extra: val
    }
}

Dans mon cas, il y a deux problèmes :

1) objet m doit mettre à jour son type après que le add() a été appelé pour refléter l'ajout d'un nouveau champ

2) le nom du nouveau champ est paramétré (ce n'est pas toujours le cas). extra par exemple)

Le premier problème peut être résolu en utilisant la définition de la classe et en utilisant d'une manière ou d'une autre la fonction TypeThis pour réajuster le type, mais je n'ai pas pu trouver suffisamment de documentation sur la manière de l'utiliser.

Toute aide ou conseil est le bienvenu. Merci de votre compréhension.

5voto

jcalz Points 30410

Introduction de TypeScript 3.7 fonctions d'affirmation qui peut être utilisé pour restreindre le type d'arguments transmis ou même this . Les fonctions d'assertion ressemblent à les protections de type définies par l'utilisateur mais vous ajoutez un asserts avant le prédicat de type. Voici comment vous pourriez mettre en œuvre Extendable en tant que classe avec add() comme méthode d'assertion :

class Extendable {
    add<K extends PropertyKey, V>(key: K, val: V): asserts this is Record<K, V> {
        (this as unknown as Record<K, V>)[key] = val;
    }
}

Lorsque vous appelez m.add(key, val) le compilateur affirme que m aura une propriété avec une clé ayant le type de key et une valeur correspondante du type val . Voici comment l'utiliser :

const m: Extendable = new Extendable();
//     ~~~~~~~~~~~~ <-- important annotation here!
m.add('one', 1)
m.add('two', 2)

console.log(m.one.toFixed(2)); // 1.00
console.log(m.two.toExponential(2)); // 2.00e+0

Tout se passe comme prévu. Après avoir appelé m.add('one', 1) Vous pouvez vous référer à m.one sans avertissement du compilateur.

Malheureusement, il y a un une mise en garde assez importante ; les fonctions d'assertion ne fonctionnent que si elles ont un type explicitement annoté. Selon la norme demande d'extraction pertinente Cette règle particulière existe pour que l'analyse du flux de contrôle des appels d'assertion potentiels ne déclenche pas circulairement d'autres analyses.

Cela signifie que l'erreur suivante a été commise :

const oops = new Extendable(); // no annotation
  oops.add("a", 123); // error!
//~~~~~~~~ <-- Assertions require every name in the call target to be declared with
// an explicit type annotation.

La seule différence est que le type de oops es déduit être Extendable au lieu de annoté comme Extendable comme m est. Et vous obtenez une erreur en appelant oops.add() . En fonction de votre cas d'utilisation, cela peut être soit sans importance, soit rédhibitoire.


J'espère que cela vous aidera ; bonne chance !

Lien vers le code

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