arktypeio/arktype

Nested `type()` with an optional property decays to `object`

refi64 opened this issue ยท 6 comments

Report a bug

๐Ÿ”Ž Search Terms

nested optional object

๐Ÿงฉ Context

  • ArkType version: 2.0.0-rc0
  • TypeScript version (5.1+): 5.5.4
  • Other context you think may be relevant (JS flavor, OS, etc.):

๐Ÿง‘โ€๐Ÿ’ป Repro

import {ArkErrors, type} from 'arktype'

const T = type({b: type({a: 'number'})})  // Type<{ b: { a: number; }; }, {}>
let t = T({b: {a: 1}})
if (!(t instanceof ArkErrors)) {
  console.log(t.b.a)  // <-- works
}

const U = type({b: type({'a?': 'number'})})  // Type<{ b: object; }, {}>
let u = U({b: {a: 1}})
if (!(u instanceof ArkErrors)) {
  console.log(u.b.a)  // <-- ERROR: Property 'a' does not exist on type 'object'.
}

In the first case, the nested type works correctly. In the second case, all I did was change a to a?, but that results in the inner type becoming just object.

Fixed in 2.0.0-rc.2!

thanks for the fix! but it still seems to happen with a slightly different test case ๐Ÿ˜…

const U = type({b: type({'a?': 'number'}).or('number')})  // Type<{ b: object; }, {}>
let u = U({b: {a: 1}})
if (!(u instanceof ArkErrors)) {
  console.log(u.b.a)  // <-- ERROR: Property 'a' does not exist on type 'object'.
}

in particular now I'm calling .or('number'). It does work if I make it .or with an object type like .or({'a?': 'number'})}, though.

@refi64 Also unrelated note you don't have to nest your type calls if you don't need chained expressions- that's the beauty of a parsed syntax!

Just:

const U = type({b: {'a?': 'number'} })

To whatever depth you need!

@refi64 This is actually fixed in 2.0.0-rc.4!

works now for all my uses, thanks!

Also unrelated note you don't have to nest your type calls if you don't need chained expressions- that's the beauty of a parsed syntax!

Right, this test case was just reduced from the more complex actual usage, where the type was spread out across multiple files.