#Narrowed type is lost if additional assertion placed (`Array.find`)

1 messages · Page 1 of 1 (latest)

onyx groveBOT
#
m.a.t.t.t#0

Preview:```ts
function search(input: unknown[]) {
const foundA = input.find(x => typeof x === "string")
// ^?

const foundB = input.find(
x => typeof x === "string" && x.startsWith("foo")
)
// ^?
}```

near nymph
#

@honest talon Yeah, type predicates are meant to be "if-and-only-if" checks

#

So TS won't infer a type-predicate if it checks the type and something else

honest talon
#

maybe im misunderstanding, but is there any scenario where the additional check would cause the initial predicate to become untrue?

near nymph
#

The issue isn't really relevant for .find but type predicates can be used for else behavior, too.

onyx groveBOT
#
// TS doesn't check custom type guards, so you can annotate this as an `x is string` predicate, but it shouldn't be.
const isStringStartingWithFoo = (x: unknown): x is string => x === "string" && x.startsWith("foo");

function doThing(x: string | number) {
   if(isStringStartingWithFoo(x)) {
       x
//     ^? - (parameter) x: string
   } else {
       x
//     ^? - (parameter) x: number
   }
}
near nymph
#

Because predicates are meant to be "if-and-only-if" checks, TS assumes x is number in the else clause, even though it could really be any string that doesn't start with "foo".

#

Anyway, TS doesn't actually check the implementations of custom type guards, so you can 'fix' your original usage with an explicit annotation:

const foundB = input.find(
    (x): x is string => typeof x === "string" && x.startsWith("foo")
)
honest talon
#

ah okay, bummer 😦 im working with AST nodes and trying to keep a clean seperation between the file this code is in, and the other file which has a lot of AST verbiage

seems like i'll unfortunately have to break that clean seperation with a very messy

const root = ast.defs.find(
  (def): def is ObjectTypeDefinition => is.objectType(def) && def.name.value === 'Query'
)
#

would be cool if boolean-returning functions carried metadata from the first true over onto the second true

near nymph
#

Depending on how runtime efficient it has to be:

ast.defs.filter(is.objectType).find(def => def.name.value === "Query")
honest talon
#

ah okay, yeah performance is not a big concern here so i suppose I could do that. thanks!

near nymph
#

But yeah, maybe there'll be 'one-sided-type-predicates' eventually. Stuff like .filter and .find are cases where they'd be useful

honest talon
#

you people in the typescript space have the most incredible vocabulary, how do you all come up with these names??