typescript - TS hjälpverktygstypinformation förlorad med "typeof" operatorn


Jag hittade nyligen vad som ser ut som en situation där TS typeof-operatorn förlorar viktig typinformation. Jag misstänker att det i själva verket handlar om ett missförstånd från min sida, men lyckligtvis är det lätt att illustrera:

const omit = <T extends object, K extends keyof T>(dict: T, key: K) => {
    return dict as Omit<T, K>;
};

// implicit object
const obj = { foo: 1, bar: 2 };
// full type info available after "omit"
const obj2 = omit(obj, "bar");
// type info is "lossy"
type O2 = typeof obj2;

I vs-code när jag hovrar över obj2 uttrycks dess typ som: Omit<{foo: number, bar: number}, "bar">. Detta är både vad jag förväntade mig och ville ha. Men när jag hovrar över typen O2 får jag en typ av { foo: number }.

Du kan se hur dessa två typer är lika men den första innehåller mer typinformation eftersom den har bevarat objektets övergripande form tillsammans med utelämnandet från den formen.

Detta gäller också i den något mer explicita situationen där den ursprungliga objektets typ anges:

// explicit object
type Start = { foo: number, bar: number};
const obj3: Start = {foo: 1, bar: 2};
// full type info available on obj4
const obj4 = omit(obj3, "bar");
// again "reduced" to just the remaining props
type O4 = typeof obj4;

Finns det något sätt på vilket den fullständiga typinformationen kan fångas av en nedströms typpdefinition som O2 eller O4? Jag förstår att i många fall är detta reducerade tillstånd faktiskt att föredra eftersom det både är enklare och korrekt, vilket gör det lättare att förstå, men i mer komplexa miljöer är det användbart att bevara denna saknade information.

Typescript-lekplats


Jag har märkt att om jag skapar en identitetsfunktion och tilldelar en annan variabel genom identitetsfunktionen bevaras typinformationen. Detta är användbart men svarar inte helt på min fråga.

Exempel :

const omit = <T extends object, K extends keyof T>(dict: T, key: K) => {
    return dict as Omit<T, K>;
};

function identity<T>(thing: T):T {
    return thing;
} 

// implicit object
const obj = { foo: 1, bar: 2 };
// full type info available after "omit"
const obj2 = omit(obj, "bar");
const myObj = identity(obj2);
type O2 = typeof myObj;

typningen för både obj2 och myObj är densamma och komplett; O2 är fortfarande förlustfull.