Eroarea Typescript TS2558 și semnificația lui keep<number>


Încerc o problemă de TypeScript pe exercism.com și văd codul de testare după cum urmează.

import {keep, discard} from './strain'

describe('strain', () => {
  it('keeps on empty array returns empty array', () => {
    expect(keep<number>([], (e: number) => e < 10)).toEqual([])
  })

Am încercat să scriu strain.ts astfel

 export function keep(list: number[], fn: Function): number[] {

dar am primit o eroare

strain.test.ts(5,12): error TS2558: Expected 0 type arguments, but got 1.

Ce înseamnă keep < number >()? Și cum rezolv eroarea TS2558?

Răspuns #1

Cred că încearcă să te învețe conceptul de generice în TypeScript. Te rog să citești documentația despre ele sau să încerci câteva articole pe blog despre elementele de bază ale generice în TypeScript.

Nu sunt sigur ce anume este prima ta întrebare. Dacă întrebi ce înseamnă <number>, atunci vei găsi răspunsul în documentație. Pe scurt, este un argument de tip. Este folosit cu clase generice și metode/funcții generice.

Poți să te gândești la Argumentul de tip aproximativ ca la un marcator pentru un tip într-o funcție șablon, care va fi dedus (aproximativ „ghicit”, simplu spus) atunci când clasa generică este creată sau funcția generică este apelată. Folosesc termeni foarte simpli și care nu sunt 100% corecți din punct de vedere tehnic.

A doua ta întrebare este despre cum să remediezi problema. Mai întâi, trebuie să înțelegi că codul actual al funcției tale nu este generic, deoarece function keep() nu primește un argument de tip, și exact asta îți spune și eroarea: Hei, invoci keep<number>(...) de parcă ar fi o funcție generică cu tip number, dar keep nu primește un argument de tip! Adică, nu există loc unde să introduci number!!.

Deci, pentru a-l repara, trebuie să faci funcția generică prin „oferirea unui loc unde să introduci acel tip”. Uite asta:

export function keep<T>(list: T[], fn: (x: T) => boolean): T[] {
  // your code goes here
  // this is what they want you to implement
}

Observați semnătura: aceasta primește un array de T (prin analogie cu string[] ca listă de string-uri sau number[] ca listă de number-uri). Tipul specific de T va fi determinat în fiecare loc de unde este apelat keep().

De exemplu, compilatorul TypeScript va înțelege că în invocarea keep(["a", "b", "c"], text => text !== "b"), T este de fapt tipul string. În timp ce, în keep([1, 2, 3, 4], num => num % 2 === 0), T este un number.

Sper că ai înțeles ideea și că îți dai seama singur cum să scrii corpul funcției.

Câteva note nesemnificative.

  • Genericele sunt un instrument foarte puternic pentru verificarea tipurilor și scrierea de cod generalizat capabil să funcționeze cu diverse tipuri. Trebuie să îl înțelegi în cele din urmă. Nu-ți face griji dacă nu prinzi fiecare detaliu. Acest aspect are multe detalii complicate.

  • Argumentul(e) de tip poate fi mai mult de unul:

    function myFunction<T1, T2, T3>(t1: T1, t2: T2): T3 {
      // ...
    }
    
  • Argumentul(i) de tip poate au nume arbitrare, nu doar „T”:

    function myFunction<A, B>(a: A): B {
      // ...
    }
    
  • Este mult mai mult de atât! ;)