Takie tam proste albo i trudne ćwiczenie w TS. Piszemy funkcję pluck na kilka sposobów, analizujemy temat, rozszerzamy swoją wiedzę w TS. Zaczynajmy.

Ok, tak wygląda ta funkcja w jej pierwszej postaci:

function pluck1<T, K extends keyof T>(o: T, propertyNames: K[]): T[K][]{
    return propertyNames.map((n) => o[n] );
}

Jesteśmy w stanie ogarnąć, co tu się dzieje? Jak nie, to staramy się to wypróbować:

function pluck1<T, K extends keyof T>(o: T, propertyNames: K[]): T[K][]{
    return propertyNames.map((n) => o[n] );
}

const obj332 = {a:1, b: 2, c: 3};
const plucked = pluck1(obj332, ['a', 'b']); 
console.log(plucked) // [1,2]

Ok, fajnie. Czym jest ten return type? Zobaczmy, czy sami potrafimy wydedukować, aplikując to, co już znamy:

type PluckRetType1 = ReturnType<typeof pluck1>
//type PluckRetType1 = any

No ten util wiele nam nie powiedział, choć to, że funkcja może zwrócić dosłownie wszystko w formie tablicy to już jakaś informacja jest. Drążymy dalej temat, to jest funkcja generyczna, czy ReturnType rozkmini nam temat, jak podamy generyczne argumenty?

type PluckRetType2 = ReturnType<typeof pluck1<{a: number, b: number, c: number}, keyof {a: number, b: number, c: number} >>
//type PluckRetType2 = number[]

Teraz podaje, że number. Ok, zmieńmy co nieco i zobaczmy co z tego wyjdzie:

type PluckRetType2 = ReturnType<typeof pluck1<{a: number, b: string, }, "a"|"b"  >>
// type PluckRetType2 = (string | number)[]

Ok, czyli tablica mieszana, gdzie mogą być stringi i liczby. Dobra, to teraz pomyślmy, czym jest ten typ zwracany. Zróbmy tak: podmieńmy go na coś, co już znamy, a co, innymi słowami, opisze to, co podejrzewamy, i zobaczmy, czy będzie problem:

function pluck1<T, K extends keyof T>(o: T, propertyNames: K[]): T[keyof T][]{
    return propertyNames.map((n) => o[n] );
}

const obj332 = {a:1, b: 2, c: 3};
const plucked = pluck1(obj332, ['a', 'b']); 
console.log(plucked) // [1,2]

Problemu nie ma, a ten keyof już znamy. To taka sztuczka, aby właśnie z obiektu wyciągnąć typy wszystkich wartości, jakie klucze mogą zwrócić.

Znaczy – keyof T to unia kluczy. T[keyof T] to unia wartości, jakie są pod kluczami w T. Znak tablicy to tablica, to co przed [] to jej typ. Proste? Chyba tak.

Ok, a teraz jak zrobić, aby można było podawać argumenty po ludzku? Czyli po przecinku?

Takie rzeczy najbardziej rozwalają nam głowę, jak się dopiero co uczymy. Ok, oto patent:


function pluck1<T, K extends keyof T>(o: T, ...propertyNames: K[]): T[keyof T][]{
    return propertyNames.map((n) => o[n] );
}

const obj332 = {a:1, b: 2, c: 3};
const plucked = pluck1(obj332, 'a', 'b'); 
console.log(plucked) // [1,2]

Spreada używamy na nazwie argumentu. Po drugiej stronie nie używamy. Druga strona (prawa) reprezentuje typ tych wszystkich argumentów propertyNames, do kupy.

Ok, wydłużyła się ta lekcja, reszta o pluck w następnej, bo nie chcę za bardzo przytłoczyć. Bo trochę ta składnia może namieszać we łbie, nie oszukujmy się.

Do następnego razu!