Repository navigation
Description
TypeScript Version: 2.2.2, 2.4.0
Code
interface A {
a: number;
}
interface B extends A {
b: number
}
export type IFieldConfig<TData> = { name: keyof TData };
export type TFieldConfigMap<TData> = {[P in keyof TData]: IFieldConfig<TData> & { name: P } };
let AFields: TFieldConfigMap<A> = {
a: { name: 'a' }
};
let BFieldsFailed: TFieldConfigMap<B> = Object.assign({}, AFields, {
b: { name: 'b' }
});
let BFieldsFailedToo: TFieldConfigMap<B> = Object.assign({}, AFields, {
b: { name: <keyof B>'b' }
});
let BFieldsWorkaround: TFieldConfigMap<B> = Object.assign({}, AFields, {
b: { name: <keyof Pick<B, 'b'>>'b' }
});
const BMap: {[P in keyof B]: P} = {
a: 'a',
b: 'b'
}
let BFieldsWorkaround2: TFieldConfigMap<B> = Object.assign({}, AFields, {
b: { name: BMap.b }
});Expected behavior:
compile flawlessly
Actual behavior:
failure to deduce types of both BFieldsFailed
Type 'TFieldConfigMap & { b: { name: string; }; }' is not assignable to type 'TFieldConfigMap'. Types of property 'b' are incompatible.
Type '{ name: string; }' is not assignable to type 'IFieldConfig & { name: "b"; }'.
Type '{ name: string; }' is not assignable to type 'IFieldConfig'.
Types of property 'name' are incompatible.
Type 'string' is not assignable to type '"a" | "b"'.
and BFieldsFailedToo
Type 'TFieldConfigMap & { b: { name: "a" | "b"; }; }' is not assignable to type 'TFieldConfigMap'.
Types of property 'b' are incompatible.
Type '{ name: "a" | "b"; }' is not assignable to type 'IFieldConfig & { name: "b"; }'.
Type '{ name: "a" | "b"; }' is not assignable to type '{ name: "b"; }'.
Types of property 'name' are incompatible.
Type '"a" | "b"' is not assignable to type '"b"'.
Type '"a"' is not assignable to type '"b"'.
I'm not sure if it is a bug in a second case.
Activity
jcalz commentedon Oct 11, 2017
If you want to assign something to
TFieldConfigMap<B>, then the compiler wants to be sure that itsbproperty is of type{name: 'b'}. In the first case, you are passing in the value{ name: 'b' }, which is being inferred to be of type{ name: string }:So it warns you. The simplest fix here is to explicitly narrow the value to the type
{ name: 'b' }. This works:Your second example uses
keyof Bwhich is'a' | 'b'. That's not'b', so the compiler is warning you.Your third example is using
keyof Pick<B, 'b'>which is a verbose way of saying'b', and so it works.So what bug do you think you're looking at? That automatic literal inference is not aggressive enough? I, myself, would like a way to tell TypeScript "infer the narrowest possible type, please" without having to redundantly write out literals as both values and types, as mentioned in #17943, but that's apparently closed as a design limitation. Is this a duplicate of #17943?
attatrol commentedon Oct 11, 2017
Joe Calzaretta (@jcalz)
Yes, it is.
mhegazy commentedon Oct 25, 2017
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.