6 votes

Comment écrire des protections de type avec no-unsafe-any activé ?

J'essaie de resserrer mon code TS en utilisant un ensemble de règles lint plus strictes, mais je me débats avec ce qui devrait être des utilisations légitimes du dynamisme.

Je suis en train de faire une garde de type pour détecter si quelque chose est itérable (pour l'envelopper dans un tableau si ce n'est pas le cas), et je n'ai aucune idée de ce qu'il faut dire à TS autre que de supprimer la règle de lint pour dire que c'est kosher :

function isIterable(obj: any): obj is Iterable<unknown> {
    return obj && typeof obj[Symbol.iterator] === 'function';
}

J'ai essayé de changer ceci en :

function isIterable(obj: undefined | {[Symbol.iterator]?: unknown}): obj is Iterable<unknown> {
    return !!obj && typeof obj[Symbol.iterator] === 'function';
}

qui se compile sans utiliser any mais ce n'est pas utile, car je veux lui passer des valeurs de type inconnu.

Existe-t-il une manière "propre" de dire "oui, je veux vraiment m'appuyer sur le retour de JS" ? undefined pour accéder à une propriété qui n'existe pas sur un objet" ? Surtout que c'est un peu l'intérêt d'écrire des protections de type.

5voto

jcalz Points 30410

Je ne sais pas si quelque chose comme no-unsafe-any vous permet d'acheter trop de choses à l'intérieur de l'espace de travail. mise en œuvre d'un garde de type défini par l'utilisateur puisque l'intérêt d'une telle protection de type est de permettre au compilateur de restreindre les valeurs qu'il ne peut normalement pas faire par le biais du rétrécissement intégré du flux de contrôle. Je comprendrais certainement que l'on suspende une règle d'alignement à l'intérieur d'une telle implémentation.

Mais je pense que vous pouvez obtenir presque le comportement que vous recherchez de cette manière :

function isIterable(obj: unknown): obj is Iterable<unknown> {
  if ((typeof obj !== 'object') || (obj === null)) return false; 
  // obj is now type object
  const wObj: { [Symbol.iterator]?: unknown } = obj; // safely widen to wObj
  return typeof wObj[Symbol.iterator] === 'function'; 
}

Il y a quelques obstacles à franchir, mais l'idée est d'utiliser le rétrécissement du flux de contrôle pour rétrécir unknown a object puis élargir object spécifiquement à un type avec une propriété optionnelle que vous essayez de vérifier (cela se fait en introduisant une nouvelle variable). Enfin, vérifiez le type de cette propriété sur le type élargi. Puisque la clé de propriété que vous vérifiez est un type de symbole, vous devez mentionner le nom de la propriété particulière dans le type élargi. Si la clé de propriété est une chaîne de caractères, vous pouvez vous contenter d'utiliser un élément de type signature de l'indice de la chaîne de caractères :

function isPromise(obj: unknown): obj is Promise<unknown> {
  if ((typeof obj !== 'object') || (obj === null)) return false;
  // obj is now type object
  const wObj: {[k: string]: unknown} = obj; // safely widen to wObj
  return typeof wObj.then === 'function';
}

Quoi qu'il en soit, j'espère que cela vous rapprochera de votre objectif. Je vous souhaite bonne chance !

1voto

Josh Points 175

Une autre bonne stratégie consiste à utiliser Partial avec un as moulage.

interface RegularForm {
    regular: number;
}

interface FancyForm extends RegularForm {
    fancy: string;
}

const isFancyForm = (instance: RegularForm): instance is FancyForm =>
    (instance as Partial<FancyForm>).fancy !== undefined;

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