Typescript: 3.6.4 reduced the never type on custom object type

Created on 14 Oct 2019  路  5Comments  路  Source: microsoft/TypeScript


TypeScript Version: 3.6.3 and 3.6.4


Search Terms:

  • reduce type to never

Code
I have updated typescript to v3.6.4 from v3.4.5.
In a single typed object, the property can have the different type.
The problem is caused when i need to set the value of specific property of the object dynamically. The type object is reduced never type.
I solved the this issue by wrapping as assertion. However, I think that typescript not throw the error. The example code is as below.

interface RowAttributes {
  rowNum: boolean;
  checked: boolean;
  disabled: boolean;
  height?: number;
  expanded?: boolean;
}

type RowAttributeValue = RowAttributes[keyof RowAttributes];

const attr: RowAttributes = { rowNum: true, disabled: true, checked: true };

function setRowAttribute(
  attrName: keyof RowAttributes,
  value: RowAttributeValue
) {
  attr[attrName] = value;
}

Expected behavior:
TypeScript not to show the error about the typings.

Actual behavior:
The compile-time error is thrown.
釀夅叧釀忈叧釀呩叺釂剦釁a喓 2019-10-14 釀嬦叐釀掅叜 3 09 29

Playground Link:
https://www.typescriptlang.org/play/?target=99&ssl=18&ssc=2&pln=1&pc=1#code/JYOwLgpgTgZghgYwgAgEoHsDuBBMYrABGArpAM7IDeAUMslFgHLEC2AXMoeugDYRwgA3LWQIAFhAQBrCABMOXXvyEjZwMnEJ95nbnwHC6E4AHMxYAPwcQrQtEPIIADwAOA2XKu6lB6gF9qajAATxcUDBw8AhJIADU4HmIUAF40LFx8IlIIMgBtGWD0GDTIzJicgF1hagR0EDIwZDgojgiM6OyKVMp6JlYOfCSAGmQ1DS05Aahh0QlpSeRBlD9qmGIQBDBgOuQyCDA2qKzIAAoRZvxGOBYIDgKikvbjnKGRADcEpNb0o-L4xIg1AAlFRzlFchcoFcbhVkKkPgDhH4gA
Related Issues:

Working as Intended

Most helpful comment

@fatcerberus I have a PR that implements that internally to fix a bug, but I haven't done the work to surface the type constructor as a new operator. I'm considering putting a proposal together for write indexed access type.

All 5 comments

This was updated in 3.5 by #30769, and working as intended.

To be clear on why this is an error, the type system is only looking at the types. If all you know is that you have a keyof T but not which keyof T, and you want to write a value at T[keyof T], then you need an intersection of the selected property types to guarantee the access is sound. In this case you get never because number & boolean & undefined is an empty intersection--there's no value you can provide that's guaranteed to be safe.

While many of the errors introduced by #30769 are annoying, this one is actually good: there's no guarantee at the type level that value is a compatible value for whatever property attrName happens to be, and the compiler is alerting you to this fact. For example, setRowAttribute("disabled", -345) is a perfectly legal call of your function but prior to #30769 would silently write the wrong type to attr.disabled!

You can work around the error by making the function generic, which also has the bonus of better enforcing you get a compatible value:

function setRowAttribute<K extends keyof RowAttributes>(
    attrName: K,
    value: RowAttributes[K]
) {
  attr[attrName] = value;
}

I'll agree that having an indexed access type reduced to never is confusing, though.

@jack-williams On a side note:

value: RowAttributes[K]

Per our discussion a few months back, this is a case where I'd really like to be able to explicitly ask for the "write type" RowAttributes:=K The generic function as written is not 100% type safe, even though the type system accepts it. For example right now one could still accidentally write the wrong type given a dynamic key:

// randomly select a key just to illustrate the blind spot in the type system
let key: keyof RowAttributes = Math.random() > 0.5 ? "disabled" : "height";
setRowAttribute(key, 150);

@fatcerberus I have a PR that implements that internally to fix a bug, but I haven't done the work to surface the type constructor as a new operator. I'm considering putting a proposal together for write indexed access type.

This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Was this page helpful?
0 / 5 - 0 ratings