2016-12-20 13 views
8

Mam funkcja, która buduje obiekt, na przykład:Export typ zwracany funkcji w maszynopisie

function toast() { 
    return { 
    a: "a", 
    b: "b" 
    } 
} 

mogę określić rodzaj funkcji jak

type ToastFunctionType = typeof toast 

Ten typ byłoby

() => { a: string; b: string; } 

Jednak chcę tylko typ wartości zwracanej. Czy można wyodrębnić typ zwracanej wartości tostów? W moim przypadku użycia, rzeczywiste wartości obiektów używają dość szczegółowych ogólnych argumentów typu. Wnioskowanie typów czyni je odpowiednimi i chciałbym uniknąć zachowania bardzo szczegółowego interfejsu (który muszę wyeksportować).

Co chcę w przypadku tosty tylko

{ a: string; b: string; } 

Odpowiedz

10

Tak, to możliwe. Sztuką jest, aby mieć gdzieś jakąś wartość, która jest zadeklarowana z potrzebnym rodzajem (typ zwrotu toast()) bez wywoływania toast(). Możesz to zrobić, wprowadzając inną funkcję, która zwraca wartość odpowiedniego typu (rzeczywistą wartością jest null), a następnie tworząc zmienną i przypisując jej wartość zwróconą przez tę funkcję, a następnie pobierając typeof z tego.

Nie mogłem znaleźć sposobu bez dodawania niewykorzystanej zmiennej, ale ponieważ zmienna została zainicjowana przez null, która jest natychmiast zwracana z funkcji, przypuszczam, że obciążenie środowiska wykonawczego jest pomijalne. Oto kod:

function toast() { 
    return { 
    a: "a", 
    b: "b" 
    } 
} 

function getReturnType<R> (f: (...args: any[]) => R): {returnType: R} { 
    return null!; 
} 

// dummy variable, used for retrieving toast return type only 
let toastType = getReturnType(toast); 

export type ToastReturnType = typeof toastType.returnType; 

UPDATE lutego 2018

W nadchodzącym wydaniu 2.8, istnieją some new language features które umożliwiają bez angażowania zmienne fikcyjne i funkcje.

Ten przykład kompiluje z maszynopis @ następnego:

export function z() { 
    return {a: 1, b: '2'} 
} 

export function v() { 
} 

type ReturnType<T extends (...args: any[]) => any> = 
    T extends (...args: any[]) => infer R ? R : never; 

export type RZ = ReturnType<typeof z>; // { a: number; b: string; } 
export type RV = ReturnType<typeof v>; // void 
+1

Neat sztuczki! Sam bym tego nie wymyślił. Wygląda nieco hackish, ale korzysta z naszej aplikacji, usuwając długie deklaracje z 2 liniami. Szkoda, że ​​nie można użyć wyrażenia po typeof (coś podobnego do typeof (ExtractReturnType (toast)), które byłoby bardziej czytelne niż deklaracja zmiennej, po której następuje typeof. – user3711864

+1

To nie zadziała, jeśli 'strictNullChecks' jest włączony, wystąpi błąd przy 'return null'. – Louis

+2

@Louis naprawiony, dziękuję. Jest to jeden z nielicznych przypadków, kiedy musisz użyć operatora asercji nie-null z' null'. – artem

Powiązane problemy