Jak deklarovat, že objekt splňuje Record s funkcemi, které přijímají libovolný počet argumentů v TypeScriptu?
Jak deklaruji objekt, který umožňuje TypeScriptu odvodit nejpřísnější typ, ale zároveň omezuje jeho hodnoty na funkci, která vrací řetězec pro libovolný počet parametrů funkce.
Například
const stringFactory = {
a: (): string => '',
b: (input: Array<string>): string => input.join(' '), // error
} satisfies { [K: string]: (...params: Array<unknown>) => string };
Nicméně to vede k chybě
Type '(input: Array<string>) => string' is not assignable to type '(...params: unknown[]) => string'. Types of parameters 'input' and 'params' are incompatible. Type 'unknown' is not assignable to type 'string[]'.ts(2322)
Také jsem se pokusil (i) anotovat objekt stringFactory typem { [K: string]: (...params: Array<unknown>) => string }. To vede ke stejné chybě
(ii) použití varianty záznamu nebo rozhraní
const stringFactory = {
a: (): string => '',
b: (input: Array<string>): string => input.join(' '), // error
} satisfies Record<string, (...params: Array<unknown>) => string }>;
(iii) Nahrazením unknown výrazem never to funguje, ale zdá se to být méně než ideální řešení
const stringFactory = {
a: (): string => '',
b: (input: Array<string>): string => input.join(' '), // error
} satisfies Record<string, (...params: Array<never>) => string }>;
(iv) Raději bych nepoužíval any
Odpověď č. 1
Správný supertyp pro všechny funkce, které vracejí string, je (...params: never) => string, používající nemožný typ never, nikoli (...args: unknown[]) => string.
To proto, že funkce jsou kontrvariantní ve svých parametrech, podívejte se na poznámky k vydání TS pro --strictFunctionTypes pro více informací a odkazů o kontravariantnosti.
Funkce (input: Array<string>): string => input.join(' ') není (...params: unknown[]) => string, protože ta druhá musí přijmout jakékoliv argumenty, které chce volající předat. Taková funkce by mohla být volána například jako f(2) a vaše implementace by pak zkusila použít neexistující metodu join() na number. Ups.
Na druhou stranu je to zcela přijatelný (...params: never) => string, protože tento typ nelze bezpečně vůbec volat... nikdy nenajdete seznam argumentů typu never, který byste mu mohli předat. Takže se nikdy nesetkáte se způsobem volání (...params: never) => string, který by způsobil, že (input: Array<string>): string => input.join(' ') selže.
Takže správný způsob, jak psát svůj kód, je
const stringFactory = {
a: (): string => '', // okay
b: (input: Array<string>): string => input.join(' '), // okay
} satisfies { [k: string]: (...params: never) => string };
Odkaz na kód na playgroundu
