11 votes

Typescript - Comment interdire l'utilisation de deux alias de type résolvant le même type de manière interchangeable ?

Disons que j'ai deux ou plusieurs alias de type, comme tel :

declare type A = string;
declare type B = string;

J'ai des variables de ces types, ainsi que des fonctions qui opèrent sur elles.

const a1: A = "example of a";
const b1: B = "example of b";

function withA(a: A){
    console.log(a);
}

function withB(b: B){
    console.log(b);
}

Je voudrais que le code suivant soit une erreur, mais il ne l'est pas :

withA(b1);
withB(a1);

Comment puis-je y parvenir ? Je dois également être en mesure d'initialiser les variables avec une chaîne de caractères (je suppose avec un cast). Cependant, une fois initialisés, je ne veux pas que les types soient "implicitement équivalents" et je veux que le compilateur interdise leur utilisation interchangeable.

J'aimerais également ne pas avoir à utiliser de classes, comme décrit ici : TypeScript - types de chaînes spécifiques

14voto

devilmaster Points 439

Les alias de type, comme leur nom l'indique, n'ajoutent rien au type qu'ils aliasent. Ainsi, en ce qui concerne TS, les deux A y B sont du même type, à savoir string .

Ce que vous pouvez faire, c'est utiliser des types de marque. Il s'agit d'une technique où vous prenez le type de base ( string dans ce cas) et l'intersecter avec un type d'objet avec une propriété de manière à rendre le type structurellement incompatible avec toute autre chose du point de vue du compilateur avec. La propriété n'a pas besoin d'exister au moment de l'exécution, elle est juste là comme un marqueur pour le compilateur :

type A = string & { __brand: "A"};
type B = string & { __brand: "B"};

const a1: A = makeA("example of a");
const b1: B =  makeB("example of b");

function makeA(s: string) {
    return s as A
}
function makeB(s: string) {
    return s as B
}
function withA(a: A){
    console.log(a);
}

function withB(b: B){
    console.log(b);
}

withA(b1); // error
withB(a1); // error

Les fonctions d'utilité makeA y makeB ne sont pas strictement nécessaires, vous pouvez simplement utiliser une assertion de type lorsque vous affectez l'élément string mais ils rendent le DX meilleur.

Note : Il existe deux propositions pour formaliser cette technique dans le système de types ( Structurelle tag type marques y Nominal unique type marques ) mais aucun n'est fusionné à l'heure où nous écrivons ces lignes, peut-être que dans une future version de TS nous aurons l'un de ces éléments.

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