Weboldal keresés

Hiányos típuskövetkeztetés a TypeScriptben


A következő kódom van, amely a megjegyzett helyen TS2322 típushibához vezet:

interface Environment<Position, Result, Results> {
    listResults(results : Results) : Iterable<[Position, Iterable<Result>]>
}

function* flatListResults<E extends Environment<P, R, Rs>, P, R, Rs>(
    env : E, results : Rs) : Iterable<[P, R]>
{
    for (const [p, rs] of env.listResults(results)) {
        for (const r of rs) {
            yield [p, r];
        }
    }
}

function test(env : Environment<number, string, [number, string[]]>, results : [number, string[]]) {
    for (const [p, rs] of env.listResults(results)) {
        let q : number = p // type checks successfully
    }
    for (const [p, r] of flatListResults(env, results)) {
        let q : number = p // yields error TS2322: Type 'unknown' is not assignable to type 'number'
    }
}

Ezt a típushibát hibának tekinteném. Egyetértesz?

Válasz #1

Ezt nem tekintik TypeScript hibának; inkább egy hiányzó funkciónak számít.


A probléma egy ilyen hívásaláírással:

declare function flatListResults<E extends Environment<P, R, Rs>, P, R, Rs>(
  env: E, results: Rs): Iterable<[P, R]>;

az, hogy nincsenek inferenciahelyek a P vagy R típusú paraméterekhez. A env és a results paraméterek E és Rs típusúak, így amikor meghívod a függvényt, a fordító képes kikövetkeztetni az E-t az env argumentum típusából és az Rs-t a results argumentum típusából. De nincs sehol, ahol a fordító kikövetkeztethetné a P-t és a R-t.

Előfordulhat, hogy azzal érvelne, hogy az E-re vonatkozó generikus megszorítás kellő információt nyújt: mivel E extends Environment<P, R, Rs>, nem használhatná-e a fordító az E típusának és a megszorításnak az alapján P és R kikövetkeztetésére? Talán, de egy ilyen funkciót soha nem valósítottak meg; a generikus megszorításokat nem tekintik kikövetkeztetési pontoknak. Ez a téma a microsoft/TypeScript#7234, egy hibajelentés, amelyet újrakategorizáltak mint funkciókérést (tehát hivatalosan Nem Hiba), és amelyet végül lezártak, mint nem tervezett.


Az említett problémával kapcsolatban, ha úgy találod, hogy erre szükséged van, inkább egy metszettípust kellene használnod, hogy a megszorítási információk egyértelműen megjelenjenek a függvény paramétertípusainál:

declare function flatListResults<E extends Environment<P, R, Rs>, P, R, Rs>(
  env: E & Environment<P, R, Rs>, results: Rs): Iterable<[P, R]>;

Most a env használható a P és R, valamint a Em következtetésére, és a következtetés a kívánt módon működik:

for (const [p, r] of flatListResultsBetter(env, results)) {
  let q: number = p // okay
}

Természetesen ez a refaktorálás feltételezi, hogy valóban szükséged van a E-re a típusodban kezdettől fogva. Ha a E csak arra szolgált volna, hogy kikövetkeztessük a P-t és a R-t (amit nem tud), akkor egyszerűen el lehet hagyni a E-t, és a env-et a P, R és Rs alapján írhatjuk meg:

declare function flatListResults<P, R, Rs>(
  env: Environment<P, R, Rs>, results: Rs
): Iterable<[P, R]>;

Az inferencia itt is működik, és nem cipel magával egy extra típusparamétert. Így adnám meg a függvényének a hívási szignatúráját, legalábbis a példában szereplő információk alapján.

Játszótér szeret kódolni

Kapcsolódó cikkek