question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Allow more constructs to work as type guards for `unknown`

See original GitHub issue

Search Terms

unknown type guard Related: https://github.com/Microsoft/TypeScript/pull/24439#issuecomment-394185089, https://github.com/Microsoft/TypeScript/issues/25172

Suggestion

Currently, only a very limited set of type guards are able to narrow the new unknown type:

  • Array.isArray (because it is a typeguard for arg is any[]) and probably some more in the lib files
  • instanceof
  • self-written typeguards

However to make working with unknown types less awkward, I’d like to see a couple of other constructs being able to narrow the unknown type:

let x: unknown;
// Direct equality should narrow to the type we compare to
x === "1"; // should narrow x to string or the literal "1" type, similar for other types aswell

// All these should narrow x to {prop: any}
"prop" in x;
x.prop != null;
x.prop !== undefined;
typeof x.prop !== "undefined";

// typeof should work on properties of the unknown variable
typeof x.prop === "string"; // should narrow x to {prop: string}

Use Cases

Make unknown easier to work with!

// before, very verbose!
const x: unknown = undefined!;

function hasProp1(x: any): x is {prop1: any} {
	return "prop1" in x;
}
function hasProp2(x: any): x is {prop2: any} {
	return "prop2" in x;
}
// imagine doing this for many more properties

if (hasProp1(x)) {
	x.prop1;
	if (hasProp2(x)) {
		x.prop2;
	}
}

// ===========

// after, much more concise and less overhead
const x: unknown = undefined!;
if ("prop1" in x) {
	x.prop1;
	if ("prop2" in x) {
		x.prop2;
	}
}

Checklist

My suggestion meets these guidelines:

  • This wouldn’t be a breaking change in existing TypeScript / JavaScript code
  • This wouldn’t change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn’t a runtime feature (e.g. new expression-level syntax)

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:87
  • Comments:22 (6 by maintainers)

github_iconTop GitHub Comments

42reactions
w0rpcommented, Sep 12, 2018

I would like it if type guards with unknown worked a little more like this.

let x: unknown

if (typeof x === 'object' && x !== null && 'foo' in x && typeof x.foo === 'string') {
  /* x is promoted to {foo: string} here */
}

I think the type promotion ought to work like so, if at all possible.

  1. typeof unknown === 'object' -> object | null
  2. (object | null) !== null -> object
  3. 'foo' in object -> {foo: unknown}
  4. typeof {foo: unknown}.foo === 'string' -> {foo: string}
27reactions
butchlercommented, Sep 20, 2019

Until this is fixed, this is a helper that can be used to make it easier to write manual type guards for unknown types that you expect to be nested objects:

export function isUnknownObject(x: unknown): x is { [key in PropertyKey]: unknown } {
  return x !== null && typeof x === 'object';
}

Example usage:

function example(x: unknown) {
    if (isUnknownObject(x) && isUnknownObject(x.prop) && typeof x.prop.subProp === 'string') {
        console.log(x.prop.subProp);
    } else {
        console.log('Could not find subProp');
    }
}

example({
    prop: {
        subProp: 'test',
    }
});
example({});

For more complicated use cases, using something like https://github.com/gcanti/io-ts is probably a better option than writing the type checks manually, but isUnknownObject can be useful for simple cases.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Documentation - Advanced Types - TypeScript
It just so happens that TypeScript has something called a type guard. A type guard is some expression that performs a runtime check...
Read more >
How To Do Anything in TypeScript With Type Guards
Type guards are conditional checks that allow types to be narrowed from general types to more specific ones. With type guards, we do ......
Read more >
How to use type guards in TypeScript - LogRocket Blog
Type guards enable you to instruct the TypeScript compiler to infer a specific type for a variable in a particular context, ensuring that ......
Read more >
Narrowing function return type with type guards - Stack Overflow
getPersonWithUnknown was just an example of a function that was properly throwing a type error (since unknown can't be assigned to Person )....
Read more >
Type Guard Composition - Adventures in Typescript
Finally, we define a function isNumberOrString that takes an unknown value and returns a boolean value. We use the isUnion function to combine...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found