Dalej poznajemy język TypeScript. Tym razem zrobimy sobie typeof na funkcji i zobaczymy, co to nam da. Do dzieła.

Ok, przypomnijmy sobie, jak działał typeof na prostych typach:

let someVariable = 42;

type someVarVal = typeof someVariable;

//type someVarVal = number

Jak widać wyłuskał nam typ przechowywany w tej zmiennej, czyli typ number. Teraz zobaczmy czy z obiektami jeszcze pamiętamy:

const user = {
    name: 'John',
    age: 32
  };

type UserType = typeof user;

// type UserType = {
//     name: string;
//     age: number;
// }

Wyłuskał nam definicję typu obiektu, który jest pod user przechowywany. Dla przypomnienia jak działa keyof, który używamy tylko na typach, nigdy na obiektach:

type Pt = { x: number; y: number };

type P = keyof Pt;
//'x' | 'y'

A także przypomnienie, jak działa keyof typeof, czyli obejście problemu, aby uzyskać klucze z konkretnego obiektu:

const user = {
    name: 'John',
    age: 32
  };

type UserKeys = keyof typeof user; // 'name' | 'age'

Ok, fajnie, ale my mieliśmy się skupić na typeof z funkcjami. To napiszmy jakąś funkcję:

function handleRequest(url: string, method: 'GET' |'POST'){

  }

type handleRequestType = typeof handleRequest;

//type handleRequestType = (url: string, method: 'GET' | 'POST') => void

Dostaliśmy typ/interfejs funkcji. Teraz z operatorem typeof (który wyłuskuje definicje typów z konkretnych obiektów) możemy zadziałać ze znanymi już nam utility types Parameters i ReturnValue, aby dostać się do typów parametrów oraz wartości zwracanej przez tę funkcję:

 function handleRequest(url: string, method: 'GET' |'POST'){

  }

type handleRequestParams = Parameters<typeof handleRequest>;

//type handleRequestParams = Parameters<typeof handleRequest>

type handleRequestReturnVal = ReturnType<typeof handleRequest>;

//type handleRequestReturnVal = ReturnType<typeof handleRequest>;

Już to robiliśmy, ale tak nieco bezmyślnie, teraz powinniśmy rozumieć, co się za tym kryje, wcześniej po prostu ten typeof wkuwaliśmy, teraz raczej już rozumiemy.

To jeszcze raz, na takim typie innym niż void, abyśmy to dobrze zrozumieli:

function getObj(){
    return {name: "John", age: 30 }
};

type objType = ReturnType<typeof getObj>

// type objType = {
//     name: string;
//     age: number;
// }

Ok, to ogarnijmy jeszcze interfejsy i funkcje. Najpierw – obiekt z metodą:

interface ObjectWithMethod {
    name: string;
    sayHi: (msg: string) => boolean;
  };

  let myObjWithMethod: ObjectWithMethod = {
    name: 'Jane',
    sayHi(msg: string){
        console.log(msg);
        return true;
    }
}

Ok, interfejs dla funkcji:

interface SearchFunc {
    (source: string, subString: string): boolean;
  }


  let mySearch: SearchFunc;
 
mySearch = function (source: string, subString: string): boolean {
  let result = source.search(subString);
  return result > -1;
};

Teraz fajna rzecz, czyli interfejs dla funkcji, ale wymuszający jakieś dodatkowe pola:

interface FuncWithDescription {
    (...args: any[]): any;
    description: string
  }

Dodatkowe pola musimy dodawać krok po kroku, nie da się ich upchnąć w function body przecież, ale ich brak wywołałby błąd:

const sum123: FuncWithDescription = function(a, b) {
    return a + b
  }

sum123.description = 'A function that sums two numbers'

console.log(sum123.description);

Tematu typeof i keyof nie wyczerpaliśmy, ale jeśli o funkcje idzie to na razie wszystko. Więcej TSa niedługo!