Maison >interface Web >js tutoriel >Partagez une bonne question d'entretien TS (comprenant 3 niveaux) et voyez à quel niveau vous pouvez répondre !

Partagez une bonne question d'entretien TS (comprenant 3 niveaux) et voyez à quel niveau vous pouvez répondre !

青灯夜游
青灯夜游avant
2023-01-13 20:05:292769parcourir

Partagez une bonne question d'entretien TS (comprenant 3 niveaux) et voyez à quel niveau vous pouvez répondre !

Je suis récemment tombé sur une bonne question d'entretien TS et j'aimerais la partager.

Cette question comporte 3 niveaux, examinons-les un par un.

Les exigences de la première couche sont les suivantes :

Implémentez une fonction zip pour fusionner les éléments de deux tableaux dans l'ordre, par exemple, lors de la saisie de [1,2,3], [4,5,6], Renvoie [[1,4], [2,5],[3,6]]

Cette couche prend à chaque fois un élément de deux tableaux, le fusionne et le place dans le tableau, puis continue de traiter le suivant one. Effectuez ce processus de manière récursive jusqu'à ce que le tableau soit vide.

function zip(target, source) {
  if (!target.length || !source.length) return [];

  const [one, ...rest1] = target;
  const [other, ...rest2] = source;

  return [[one, other], ...zip(rest1, rest2)];
}

Le résultat est bon :

Le premier niveau est relativement simple, regardons ensuite les exigences du deuxième niveau :

Définissez le type ts pour cette fonction zip (deux façons d'écrire)

fonction Il existe deux formes de définition :

Déclarer une fonction directement via function :

function func() {}

et déclarer une fonction anonyme et l'attribuer à une variable :

const func = () => {}

Les types de paramètres et les valeurs de retour sont tous deux des tableaux, mais les spécifiques le type n'est pas connu, vous pouvez donc écrire inconnu[ ].

Donc les définitions des deux types de fonction sont comme ceci :

Il s'agit également directement d'une fonction déclarant le type de fonction et d'une interface déclarant le type de fonction puis de l'ajouter au type de variable.

Le type d'élément spécifique n'étant pas connu, inconnu est utilisé.

Vous pouvez demander ici la différence entre any et inconnu :

Tous deux any et inconnu peuvent recevoir n'importe quel type :

Mais any peut également être attribué à n'importe quel type, mais inconnu ne le peut pas.

Ceci est simplement utilisé pour recevoir d'autres types, donc l'inconnu est plus approprié et plus sûr que n'importe quel autre.

Ce niveau est également une syntaxe ts relativement basique, et le troisième niveau devient plus difficile :

Utilisez la programmation de type pour obtenir des astuces de type précises, telles que passer des paramètres dans [1,2,3], [4,5, 6 ], alors le type de la valeur de retour doit indiquer [[1,4], [2,5],[3,6]]

Le type de valeur de retour doit être précis ici, et nous devons le déterminer en fonction du type du paramètre. Générez dynamiquement des types de valeurs de retour.

C'est tout :

Déclarez deux paramètres de type Target et Source, et la contrainte est inconnue[], qui est un type de tableau de n'importe quel type d'élément.

Ces deux paramètres de type sont les types des deux paramètres transmis.

La valeur de retour est calculée via Zip.

Ensuite, nous devons implémenter le type avancé de Zip :

Les paramètres de type transmis sont deux types de tableaux, et nous devons également en extraire chaque élément et les fusionner ensemble.

La correspondance de modèles peut être utilisée pour extraire des éléments :

Ce type peut donc être défini comme ceci :

type Zip<One extends unknown[], Other extends unknown[]> =
    One extends [infer OneFirst,...infer Rest1]
      ? Other extends [infer OtherFirst, ...infer Rest2]
        ? [[OneFirst, OtherFirst], ...Zip<Rest1, Rest2>]
        : []
      : [];

Extraire respectivement le premier élément des deux tableaux et construire un nouveau tableau. Faites ensuite cela de manière récursive pour le tableau restant jusqu'à ce que le tableau soit vide.

Cela permet d'obtenir le type avancé que nous souhaitons :

Mais si vous l'ajoutez comme valeur de retour à la fonction, une erreur sera signalée :

Parce que vous ne savez pas quels sont les paramètres lorsque vous déclarez la fonction, naturellement La valeur de Zipa7808be3c0f211b573c7d3497f62053f ne peut pas être calculée, il y aura donc une incompatibilité de type ici :

Que devons-nous faire ?

Peut être résolu avec la surcharge de fonctions :

ts prend en charge la surcharge de fonctions. Vous pouvez écrire des définitions de type pour plusieurs fonctions portant le même nom, et enfin écrire l'implémentation de la fonction, de sorte que lorsque cette fonction est utilisée, elle est utilisée. sera basé sur le type du paramètre pour correspondre aux types de fonctions.

La fonction que nous utilisons pour la programmation de types ne signalera pas d'erreur si elle est écrite de cette manière.

Jetons un coup d'oeil :

Pourquoi le type de valeur de retour est-il incorrect ?

En fait, le type de fonction correspondant est correct pour le moment, mais celui déduit n'est pas un type littéral.

Vous pouvez ajouter comme const à ce moment.

Mais ajouter as const déduira readonly [1,2,3]

Les types ne correspondront pas, vous devez donc ajouter readonly:

à la déclaration des paramètres de type

Mais le type de fonction Zip ne correspond plus.

Devrions-nous ajouter en lecture seule à tous les endroits où ce type est utilisé ?

Pas besoin, pouvons-nous simplement supprimer la modification en lecture seule ?

Typescript a un type avancé intégré en lecture seule :

Vous pouvez ajouter une modification en lecture seule à chaque index du type d'index :

Mais il n'y a pas de type avancé qui supprime la modification en lecture seule. Nous pouvons implémenter. nous-mêmes :

Construisez un nouveau type d'index en utilisant la syntaxe du type de mappage et ajoutez -readonly pour supprimer la modification en lecture seule.

Certains étudiants peuvent se demander : le type tableau est-il également un type index ?

Oui, le type index est un type qui regroupe plusieurs éléments, donc les objets, les tableaux et les classes le sont tous.

On peut donc naturellement l'utiliser sur des tableaux :

(Pour être précis, ça s'appelle un tuple. Un tuple est un tableau avec un nombre fixe d'éléments)

Ensuite, il suffit d'utiliser Just Remove readonly from Mutable :

Réessayez :

Terminé ! Le type de valeur de retour est désormais correct.

Mais il y a un autre problème. Si le littéral n'est pas transmis directement, le type littéral ne peut pas être déduit. Cela semble être faux :

Mais n'avons-nous pas tous déclaré des types surchargés ?

Si le type littéral ne peut pas être déduit, il devrait correspondre à celui-ci :

Mais en fait, il correspond au premier :

À ce stade, changez simplement l'ordre des deux types de fonctions. Maintenant :

La situation des paramètres littéraux est toujours correcte à l'heure actuelle :

Pourquoi ?

Parce que les types de fonctions surchargées correspondent de haut en bas. Tant qu'une correspond, elle sera appliquée.

Dans le cas de valeurs non littérales, le type est number[], qui peut correspondre au type d'inconnu[], de sorte que le type de fonction prend effet.

Dans le cas des littéraux, readonly [1,2,3] est déduit, avec readonly pour qu'il ne corresponde pas à unknown[].

De cette façon, le type de fonction approprié est appliqué dans les deux cas.

Le code entier est comme ceci :

type Zip<One extends unknown[], Other extends unknown[]> = One extends [
  infer OneFirst,
  ...infer Rest1
]
  ? Other extends [infer OtherFirst, ...infer Rest2]
    ? [[OneFirst, OtherFirst], ...Zip<Rest1, Rest2>]
    : []
  : [];

type Mutable<Obj> = {
  -readonly [Key in keyof Obj]: Obj[Key];
};

function zip(target: unknown[], source: unknown[]): unknown[];

function zip<Target extends readonly unknown[], Source extends readonly unknown[]>(
  target: Target,
  source: Source
): Zip<Mutable<Target>, Mutable<Source>>;

function zip(target: unknown[], source: unknown[]) {
  if (!target.length || !source.length) return [];

  const [one, ...rest1] = target;
  const [other, ...rest2] = source;

  return [[one, other], ...zip(rest1, rest2)];
}

const result = zip([1, 2, 3] as const, [4, 5, 6] as const);

const arr1 = [1, 2, 3];
const arr2 = [4, &#39;5&#39;, 6];

const result2 = zip(arr1, arr2);

ts playground 地址

总结

今天我们做了一道综合的 ts 面试题,一共有三层:

第一层实现 js 的逻辑,用递归或者循环都能实现。

第二层给函数加上类型,用 function 声明类型和 interface 声明函数类型两种方式,参数和返回值都是 unknown[]。

第三层是用类型编程实现精准的类型提示,这一层需要拿到参数的类型,通过提取元素的类型并构造出新的数组类型返回。还要通过函数重载的方式来声明类型,并且要注意重载类型的声明顺序。

as const 能够让字面量推导出字面量类型,但会带有 readonly 修饰,可以自己写映射类型来去掉这个修饰。

其实这也是我们学习 ts 的顺序,我们先要能把 js 逻辑写出来,然后知道怎么给函数、class 等加 ts 类型,之后学习类型编程,知道怎么动态生成类型。

其中类型编程是 ts 最难的部分,也是最强大的部分。攻克了这一层,ts 就可以说学的差不多了。

【相关推荐:javascript学习教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer