5
type Test = { a: string; b: boolean; c: number }
type Key = keyof Test;

function foo(x: Key): Partial<Test> {
  return {[x]: null};
}

playground

For the above code, foo returns a Partial of Test, and the key of the return object is bound to Key, 'a' | 'b' | 'c'. However, even though the argument is the key of the Test, the null value is assignable for the Partial<Test>.

Is it intended behaviour for TypeScript?

  • This is not the problem of `Partial` type, in fact if you write `let test : Partial = {a: null}` it correctly gives you error. The problem here is `x` is unknown until runtime. So there is no way to resolve the type of `[x]` in compile time. – Ricky Mo Jun 01 '23 at 05:41
  • 2
    This is essentially [ms/TS#38663](https://github.com/microsoft/TypeScript/issues/38663); `{[x]: null}` gets its type widened to `{[x: string]: null}` which isn't *wrong* but it's kind of unhelpful, but then somehow *that* is allowed to be assignable to `Partial` which is a bug described at [ms/TS#27144](https://github.com/microsoft/TypeScript/issues/27144). So part of this is definitely not intended behavior. Does that fully address the question? If so I'll write up an answer; if not, what am I missing? – jcalz Jun 01 '23 at 15:23

1 Answers1

2

This is not an answer per se since this issue seems more like a bug or an unimplemented feature in TypeScript than an issue in your code, but here are some workarounds to this issue:

  1. Using the satisfies operator, we can ensure that the return type adheres to what we set:
function foo(x: Key): Partial<Test> {
  return { [x]: null satisfies Test[Key] }; // This checks whether 'null' is assignable to one of the values in 'Test' without changing the type of 'null'.
}
  1. The type of { [x]: null } is { [x: string]: null }, so if we set the return type (or, create a variable and set its type) using a similar syntax, we once again get the correct error:
function foo(x: Key): { [x: string]: Test[Key] } {
  return { [x]: null };
}
Eldar B.
  • 1,097
  • 9
  • 22