Comment attribuer un type à un tableau de tuples dont les entrées peuvent varier d'un tuple à l'autre ?
P粉068486220
P粉068486220 2023-09-06 22:44:17
0
2
484

En supposant que je l'ai faitfunction foo(args) {...},其中args是一个二元组数组,这样元组中的条目是相同类型的(即[T,T]),但是元组的条目可能任意变化(即[[T,T], [U,U],[V,V]]). Par exemple :

foo([ [1, 3], ["hello", "world"], [true, true], [2, 7] ]) // no error

Comment dois-je saisir le paramètrefooargspour que les types incompatibles dans le tuple génèrent une erreur de type au moment de la compilation ? Par exemple :

foo([ [1, 3], ["hello", 5], // type error here [true, true], [2, 7n] // type error here ])

Si l'erreur de type ne peut pas être affichée en ligne, il est également acceptable que l'intégralité de l'appel de fonction soit erronée.


Annexe: Est-elle disponible[SomeType , T] 类型的 2 元组(即第二个条目的类型应与第一个),但 T 仍然可以在元组之间变化[[SomeType , T],[SomeType , U],[SomeType , V]] ?

foo([ [{value: 1}, 3], [{value: "hello"}, 5], // type error here [{value: true}, true], [{value: 2}, 7n] // type error here ])

P粉068486220
P粉068486220

répondre à tous (2)
P粉948258958

Je pense que tu peux passer pourrow创建一个类型来简单地实现此目的,该类型将接受stringnumber或 布尔值.

类型 Row = string[] |布尔值[] |数字[]

Nous pouvons maintenant attribuer ce type au paramètrefoo函数的args.

function foo(args: Row[]): void { ... ... ... }

En utilisant cette définition de type, Typescript générera une erreur si vous fournissez un argument àfoooù les types d'éléments de la ligne ne correspondent pas.

C'est le terrain de jeuLien代码>.

    P粉136356287

    Pour y parvenir, nous devons utiliser desgenericsarrays et desmapped typespour mapper les éléments du tableau. Puisque nous savons que le tableau doit être un tableau de tuples de longueur 2, nous allons déduire le paramètre générique pour le premier élément du tuple et faire en sorte que le deuxième élément ait le même type. Pour obtenir le type d'un paramètre générique, nous devons utiliser le mot-cléInfer. Notez que nous devons connaître exactement (ou au moins un type de forme similaire) le type générique utilisé pour le faire fonctionner, qui dans notre cas estVariable:

    const foo = (arr: { [K in keyof T]: T[K] extends unknown[] ? T[K][0] extends Variable ? [Variable, Type] : T[K] : T[K]; }) => {}

    Cela peut sembler être tout, mais regardons les types des tableaux suivants :

    const arr = [1, '2', false]; // (string | number | boolean)[] type Arr = typeof arr;

    Comme vous pouvez le constater, le type n'est pas exactement le même que celui que nous avons dans l'arr. Le compilateur étend le type pour garantir que nous pouvons modifier les éléments du tableau. Pour faire savoir au compilateur que le tableau est en lecture seule, nous devons utiliser l'assertionconst:

    const arr = [1, '2', false] as const; // readonly [1, "2", false] type Arr = typeof arr;

    Ça a l'air bien maintenant, cela signifie que nous devons définir le tableau transmis àfooen lecture seule, et comme les tableaux en lecture seule sont un sur-ensemble des tableaux mutables que nous obtiendrions si nous essayions de transmettre un tableau en lecture seule à An une erreur apparaîtra :

    // false type Case1 = readonly number[] extends number[] ? true : false; // true type Case2 = number[] extends readonly number[] ? true : false;

    Nous mettons donc à jour tous les types de tableaux dansfoopour qu'ils soient en lecture seule. Notez que puisque notre tableau est 2D, le tableau interne sera également en lecture seule, et les contraintes sur le tableau doivent être un tableau en lecture seule de tableaux en lecture seule :

    const foo = (arr: { [K in keyof T]: T[K] extends readonly unknown[] ? T[K][0] extends Variable ? readonly [Variable, Type] : T[K] : T[K]; }) => {};

    Test :

    declare const ctx1: Variable; declare const ctx2: Variable; declare const ctx3: Variable; declare const ctx4: Variable; declare const ctx5: Variable; declare const ctx6: Variable<{ name: string; age: number }>; foo([ [ctx1, 3], [ctx2, 'world'], [ctx3, true], [ctx4, 7], ] as const); foo([ [ctx1, 3], [ctx2, 'world'], [ctx3, true], [ctx4, 'invalid'], // error ] as const);

    Cependant, nous avons encore quelques problèmes. Par exemple, si le premier élément du tuple est une primitive deVariable,则意味着第二个参数也应该是7,而不是任何数字,如果这是一个问题我们需要获取7, qui est un nombre. Cela peut être fait en utilisant les types d'utilitairesToPrimitivede mon projet open sourcetype-samurai: p>

    type ToPrimitive = T extends string ? string : T extends number ? number : T extends null ? null : T extends undefined ? undefined : T extends boolean ? boolean : T extends bigint ? bigint : T extends symbol ? symbol : { [K in keyof T]: ToPrimitive; };

    Fonctionnalités mises à jour :

    const foo = (arr: { [K in keyof T]: T[K] extends readonly unknown[] ? T[K][0] extends Variable ? ToPrimitive extends infer PrimitiveType ? readonly [Variable, PrimitiveType] : T[K] : T[K] : T[K]; }) => {};

    Un autre problème est que si le type déduit dans notre implémentation actuellefoo实现中推断的类型是number[]estnumber[]

    , nous n'autoriserons pas les tableaux en lecture seule :

    foo([ [ctx5, [4, 5, 6]], // The type 'readonly [4, 5, 6]' is 'readonly' and cannot be assigned to the mutable type 'number[]' ] as const)
    Le correctif est très simple, nous allons vérifier si le type déduit est un tableau, puis obtenir son type d'élément et ElementType en lecture seule[] comme deuxième paramètre du tuple :

    const foo = (arr: { [K in keyof T]: T[K] extends readonly unknown[] ? T[K][0] extends Variable ? ToPrimitive extends infer PrimitiveType ? readonly [ Variable, PrimitiveType extends Array ? readonly ArrayItem[] : PrimitiveType, ] : T[K] : T[K] : T[K]; }) => {};
    Test :
    foo([ [ctx1, 3], [ctx2, 'world'], [ctx3, true], [ctx4, 7], [ctx5, [4, 5, 6]], [ctx6, {name: "Hi", age: 23}], ] as const); foo([ [ctx1, 3], [ctx2, 'world'], [ctx3, true], [ctx4, true], // error here [ctx5, [4, 5, 6]], [ctx6, 50], // error here ] as const);

    Ce qui est ennuyeux, c'est qu'il faut utiliserconst 断言。在 Typescript5.0中,const 类型参数,这样我们就可以避免const 断言partout :

    const foo = (item: T) => item // readonly [1, 2, 3] const result = foo([1,2,3])

    Malheureusement, nous ne pouvons pas les utiliser car nous faisons quelque chose avec le paramètre au lieu de lui attribuer directementTcomme type :

    const foo = (item: {[K in keyof T]: T[K]}) => item // const result: (2 | 1 | 3)[] const result = foo([1, 2, 3])

    Quoi qu'il en soit, actuellement,const 断言est le seul moyen de garantir que cela fonctionne comme prévu.

    Lien vers l'aire de jeux

      Derniers téléchargements
      Plus>
      effets Web
      Code source du site Web
      Matériel du site Web
      Modèle frontal
      À propos de nous Clause de non-responsabilité Sitemap
      Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!