Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Narrowing of keys in objects when passed to function

Tags:

typescript

Why does TypeScript not apply type narrowing on members of objects to the object type itself, such that it can be passed to another function that expects a narrowed type? How can this be fixed/circumvented without losing typesafety?

Minimal example:

type A = { key: string | null};
type B = {key: string};

function func(a: B) {};

const a: A = {key:'abcd'};
if(typeof(a.key)==='string') {
  a.key // has (narrowed) type 'string'
  func(a); // still does not work
}

The error message is:

Types of property 'key' are incompatible. Type 'string | null' is not assignable to type 'string'.

Playground

like image 627
jofel Avatar asked Sep 08 '25 10:09

jofel


2 Answers

This is ultimately a design limitation of TypeScript. It does not use type guards on an object's properties to narrow the object itself, except in the particular case where the object is a discriminated union type... and in your case, A isn't a union at all, let alone a discriminated one.

The way I'd do this for your case is to introduce a user-defined type guard function which explicitly performs the narrowing you expect: you pass in an object with a key property, and return true or false depending on whether or not this object is a valid B:

const isB = (x: { key: any }): x is B => typeof x.key === "string";

Then you use it:

if (isB(a)) {
  func(a); // okay
}

This is (give or take a function call) essentially the same logic as your code, but the compiler recognizes your intent now. Okay, hope that helps; good luck!

Link to code

like image 166
jcalz Avatar answered Sep 10 '25 06:09

jcalz


use type guards : https://www.typescriptlang.org/docs/handbook/advanced-types.html#typeof-type-guards

type A = { key: string | null};
type B = {key: string};

function func(a: B) {};

const a: A = {key:'abcd'};

const isB = (foo: A | B): foo is B => typeof a.key === "string";
if(isB(a)) {
  a.key
  func(a);
}

TS Playground

like image 20
D Pro Avatar answered Sep 10 '25 06:09

D Pro