8

I'm trying to define a TypeScript type in terms of another type.

This works:

type Result = { data: { nestedData: { foo: string; bar: string } } };

type NestedData = Result['data']['nestedData'];

But, when the data property is nullable, this doesn't work:

type Result = { data: { nestedData: { foo: string; bar: string } } | null };

type NestedData = Result['data']['nestedData'];

and results in the error:

Property 'nestedData' does not exist on type '{ nestedData: { foo: string; bar: string; }; } | null'.(2339)

How can I define my NestedData type in terms of Result, without duplicating any part of Result's typings?

Demo on TypeScript Playground

Edit: I'm getting my NestedData type from a codegen tool and I'm defining NestedData as a shorter type alias. In reality the typing is longer so I want to minimize repetition.

ruohola
  • 21,987
  • 6
  • 62
  • 97

2 Answers2

7

You can use Exclude to remove null from the union:

type NestedData = Exclude<Result['data'], null>['nestedData']

Playground Link

It makes sense to do it that way when you can't change your Result type for some reason. In other situations it would be more natural to define them this way round:

type NestedData = { foo: string; bar: string }
type Result = { data: { nestedData: NestedData } | null }
kaya3
  • 47,440
  • 4
  • 68
  • 97
  • "But in most situations it would be more natural to define them this way round:" Maybe yes, but I get my `NestedData` type from a codegen tool and I'm defining `NestedData` as a shorter type alias. – ruohola Sep 10 '21 at 12:22
  • 1
    Yep, in that case it makes sense to do it that way round, and you'll want to use `Exclude`. – kaya3 Sep 10 '21 at 12:23
  • This works with optional fields too, e.g. you can use type `NestedData = Exclude['nestedData']` if the original type is defined as `data?: ...` – Alexander Rechsteiner Dec 15 '22 at 12:50
2

Generic util for getting nullable properties:

type Result = {
    data: {
        nestedData: { foo: string; bar: string }
    } | null
};

type GetNullable<T, Prop extends keyof NonNullable<T>> = NonNullable<T>[Prop]

type NestedData = GetNullable<Result['data'], 'nestedData'>

Playground

ruohola
  • 21,987
  • 6
  • 62
  • 97