Typescript: Non-null assertion type operator `!`

Created on 28 Feb 2017  路  10Comments  路  Source: microsoft/TypeScript



TypeScript Version: 2.2.1

Code

interface Foo {
    bar: {
        baz: number;
    } | null;
}

type Baz = Foo["bar"]["baz"];  // This doesn't compile with the error: "Property 'baz' does not exist on type '{ baz: number; } | null'."
let x: Baz = 0;

Expected behavior:
I would expect there to be a way to specify bar is non-null, such as Foo["bar!"].

Actual behavior:
The code doesn't compile with the following error message:
"Property 'baz' does not exist on type '{ baz: number; } | null'."

Declined Suggestion

All 10 comments

This requires a null assertion type operator, as you noted. something of the form type Baz = (Foo["bar"])!["baz"];.

Also referenced in https://github.com/Microsoft/TypeScript/issues/13253

Another dupe: #17370

As it seems a special operator for this is no longer planned (see https://github.com/Microsoft/TypeScript/pull/17948#issuecomment-327859311), I added an example for this at https://github.com/Microsoft/TypeScript/pull/17961/commits/4d14c9fb1da5cf6f5db024e8b25c87336d834103 now.

@tycho01 This still possible somehow? Apparently the syntax used in your example is no longer valid.

I'm trying to achieve the opposite of Partial<T> to describe initialized (i.e defaults applied) to option objects (a mix of optional and required properties).

The following would be possible if ! operator or Assert<T> were available:

/**
 * Make all properties in T required
 */
type Whole<T> = {
    [P in keyof T]!: T[P];
};

Is there any alternatives?

@cvsguimaraes: it's an outstanding PR, it has never been possible yet on master. The current topic is just a sub-case of #4183.

It's not perfect, but a workaround for the example at the top is to do

type Baz = (Foo["bar"] & {"baz": {}})["baz"];

to get the deeper type. it does make the type number & {} but it at least makes the above code work

To simplify that, i made the following helper (called Get because of _.get):

type Getter<T, K extends string> = T & Record<K, {}>;
type Get<T, K extends keyof Getter<T, K>> = Getter<T, K>[K];

// Usage:
type Baz = Get<Foo["bar"], "baz">;

Fixed in https://github.com/Microsoft/TypeScript/pull/22094 by tweaking the compiler to allow partial unions for indexed types - therefore not requiring a null assertion operator.

a NonNullable type was part of #21847

Discussed this again in #22445. Conclusion, with NonNullable available now with conditional types, the original scenario should be unblocked, no reason to add new rules.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kyasbal-1994 picture kyasbal-1994  路  3Comments

weswigham picture weswigham  路  3Comments

manekinekko picture manekinekko  路  3Comments

siddjain picture siddjain  路  3Comments

Roam-Cooper picture Roam-Cooper  路  3Comments