Open
Description
Search Terms
unknown type guard
Related: #24439 (comment), #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 codeThis wouldn't change the runtime behavior of existing JavaScript codeThis could be implemented without emitting different JS based on the types of the expressionsThis isn't a runtime feature (e.g. new expression-level syntax)
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
mattmccutchen commentedon Jul 17, 2018
The use of
in
is covered by #21732. Shall we add the other checks for a property (comparison to undefined, typeof) to #21732 and call this a duplicate of #21732 + #25172?AlCalzone commentedon Jul 17, 2018
Sure, why not!
in
operator as type guard which asserts property existence #21732AlCalzone commentedon Jul 19, 2018
And one more thing:
ghost commentedon Jul 24, 2018
At the least, at
typeof foo === "object"
it should narrow toobject
. Currently remainsunknown
and the following fails:mhegazy commentedon Jul 27, 2018
Similar requests in #10715, #25172, and #21732
unknown
types #26078simonbuchan commentedon Aug 21, 2018
I was hoping
unknown
would let me have type-safe data-loading, e.g.:This to me would be a better match to TS for what #26078 wants, but I wouldn't complain about adding quick-fixes to add the missing checks!
(remember that
typeof u === "object"
should actually narrow toobject | null
- Thanks javascript!)w0rp commentedon Sep 12, 2018
I would like it if type guards with
unknown
worked a little more like this.I think the type promotion ought to work like so, if at all possible.
typeof unknown === 'object'
->object | null
(object | null) !== null
->object
'foo' in object
->{foo: unknown}
typeof {foo: unknown}.foo === 'string'
->{foo: string}
7 remaining items
butchler commentedon 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:Example usage:
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.stephenlautier commentedon Oct 28, 2020
@butchler Similar to what you suggested (infect i started with that)
The main difference is that
arg
will be partially typed so when you do checks with props they are bound to the interface so you can F2 rename safely and will also be updatedbutchler commentedon Oct 29, 2020
This is effectively the same as a type assertion (i.e.
arg as Partial<CommandCreator>
), but unlike a type assertion it does not use an explicitas
keyword and it implicitly changes the type ofarg
in the following expressions.Type assertions are fine and have to be used sometimes, but personally I would avoid using something like
isAssumedType
because 1) it is less explicit so other people reading the code might not realize a type assertion is being made and 2) it makes it very easy and convenient to use type assertions, which is probably a bad thing because type assertions should generally be avoided when possible.stephenlautier commentedon Oct 29, 2020
Yes, naming is not the best I agree (but whatever, you can call it as you want), and to be honest I only use it private in file along with some type guards so my main intention is usage in guards so far.
As you suggested
arg as Partial<CommandCreator>
doesnt work inlined within the condition e.g.Whereas with my suggestion works as following:

So again, the main benefit is that F2 rename works (which is a huge plus imo)
Anyway just wanted to share.
username-not-known commentedon Jan 26, 2021
typeof x.foo doesn't work -> Property 'foo' does not exist on type 'object'.
w0rp commentedon Jan 26, 2021
That's an example of something I would like to work, but currently doesn't.
username-not-known commentedon Jan 26, 2021
Maybe something like this works.. It does the job for me.. Here 'result' is of type unknown. So narrowing down to the required type using user defined type guard seems to be the sane type-safe solution. Or are there are other possibilities as well?
tushar-sg commentedon Jul 14, 2021
Would like to see this implemented.
Typescript still complains for the above code even though we check for all the cases before accessing the
quest
property.Using
any
instead ofunknown
takes away the benefits of using TS in the first place.rattrayalex commentedon Sep 8, 2021
I would expect
?.
to work as well with anunknown
err
, though perhaps there's a case I haven't thought of which would cause failure, eg:1valdis commentedon Dec 3, 2021
The lack of better/easier type guards for
unknown
type is why I'm not using it in try...catch blocks as well. I should be able to do simplyI don't want to overcomplicate my code just because
unknown
is so hard to work with so I'm sticking toany
, yet I'd happily useunknown
if the code above and in the other proposed examples worked.jcalz commentedon Sep 6, 2022
Crosslinking to #27706
jguddas commentedon Jan 19, 2023
Adding this kind of type of guards to Arrays, Maps and Sets could be done quite easily, Objects are be a bit more complicated.