#property does not exist on type number ... ???

1 messages · Page 1 of 1 (latest)

cedar nest
#

I have a function:

export const createTokenUsingOktaData = async (
  requestBaseUrl: string,
  oktaAuthorizationCode: string
) => {
  try {
    const { token } = await fetchOktaTokens(requestBaseUrl, oktaAuthorizationCode)
    return [308, { token }]
  } catch (err) {
    return [401, { message: (err as Error).message }]
  }
}

and an api that is trying to use that function:

  router.get('/v1/auth/callback', validate(authCallbackSchema), async (req, _res) => {
    const authorizationCode = String(req.query.code)

    const protocol = req.get('x-forwarded-proto')?.includes('https') ? 'https' : 'http'
    const baseUrl = `${protocol}://${req.get('host')}`
    const [code, result] = await createTokenUsingOktaData(baseUrl, authorizationCode)

E   if (result.token) { // E: Property 'token' does not exist on type 'number | { token: string; } | { message: string; }'.   Property 'token' does not exist on type 'number'.

Why in the world does typescript think result is possibly a number???

livid sail
#

because createTokenUsingOktaData is inferred to be returning an array, (number | { token: string; } | { message: string; })[], instead of the tuple you're intending, [number, { token: string; } | { message: string; }]
you could annotate that return type

dusty parcel
#

You can also as const the two returns.

#

But yes, it's not possible for TS to read your mind: [42, 'hello'] could mean "I want a mixed array of numbers and strings" or it could mean "I want a tuple of exactly length 2 where first element is a number and second is a string" or anything in between.

cedar nest
#

I see.. I would have thought that because a function literally returns somewhat-static values, that typescript would know that index 0 is a number, and index 1 is an object... but you are saying that's what return [0, 'foo'] as const will do?

dusty parcel
#

Yes.

tender bramble
#

If you make it a readonly array then you get those guarantees