extracting redux-like actions from type.enumerated discriminated union

Trying unsuccessfully to convert some redux/reducer-like "action" object types to arktype:
type TestAction1 = { type: 'ACTION_1', value: number }
type TestAction2 = { type: 'ACTION_2', name: string}
type TestAction = TestAction1 | TestAction2

function CreateTestAction1(): Extract<TestAction, {type: 'ACTION_1'}> {
return { type: 'ACTION_1', value: 3 }
}

const testAction1 = CreateTestAction1() // type === TestAction1
type TestAction1 = { type: 'ACTION_1', value: number }
type TestAction2 = { type: 'ACTION_2', name: string}
type TestAction = TestAction1 | TestAction2

function CreateTestAction1(): Extract<TestAction, {type: 'ACTION_1'}> {
return { type: 'ACTION_1', value: 3 }
}

const testAction1 = CreateTestAction1() // type === TestAction1
Below is how I did the conversion. The Extract on the type.enumerated results in a never and I don't follow why.
const ArkAction1 = type({ type: type.unit("ACTION_1"), value: type.number })
const ArkAction2 = type({ type: type.unit("ACTION_2"), name: type.string })
const ArkAction = type.enumerated(ArkAction1, ArkAction2)
type ArkAction = type.infer<typeof ArkAction>

function CreateArkAction1(): Extract<ArkAction, { type: 'ACTION_1'}> {
return { type: 'ACTION_1', value: 3 } // type not assignable to never
}
const ArkAction1 = type({ type: type.unit("ACTION_1"), value: type.number })
const ArkAction2 = type({ type: type.unit("ACTION_2"), name: type.string })
const ArkAction = type.enumerated(ArkAction1, ArkAction2)
type ArkAction = type.infer<typeof ArkAction>

function CreateArkAction1(): Extract<ArkAction, { type: 'ACTION_1'}> {
return { type: 'ACTION_1', value: 3 } // type not assignable to never
}
If I define the action union type in vanilla TS (from the ark inferred types) the extract works as expected:
type ArkAction1 = type.infer<typeof ArkAction1>
type ArkAction2 = type.infer<typeof ArkAction2>
type ArkAction = ArkAction1 | ArkAction2
type ArkAction1 = type.infer<typeof ArkAction1>
type ArkAction2 = type.infer<typeof ArkAction2>
type ArkAction = ArkAction1 | ArkAction2
Am I holding it wrong?
45 Replies
Dimava
Dimava2w ago
Enumerated is array.includes, not a union You need A1.or(A2) Lemme actual rewrite your code
errata
errata2w ago
are you sure? because when I look at the resulting type of the infer on the type.enumerated type ArkAction = type.infer<typeof ArkAction> it looks like this:
type ArkAction = Type<{ type: 'ACTION_1'; value: number }, {}> | Type<{ name: string; type: 'ACTION_2' }, {}>
type ArkAction = Type<{ type: 'ACTION_1'; value: number }, {}> | Type<{ name: string; type: 'ACTION_2' }, {}>
https://github.com/arktypeio/arktype/blob/da2f08d559e7c9a8e95ca513227a1496f9be3041/ark/type/__tests__/type.test.ts#L126-L130
errata
errata2w ago
No description
Dimava
Dimava2w ago
import { type } from 'arktype'

const ArkAction1 = type({ type: "'ACTION_1'", value: 'number' })
const ArkAction2 = type({ type: "'ACTION_2'", name: 'string ' })
const ArkAction = ArkAction1.or(ArkAction2)
type ArkAction = typeof ArkAction.infer

function CreateArkAction1(): Extract<ArkAction, { type: 'ACTION_1' }> {
return { type: 'ACTION_1', value: 3 }
}
import { type } from 'arktype'

const ArkAction1 = type({ type: "'ACTION_1'", value: 'number' })
const ArkAction2 = type({ type: "'ACTION_2'", name: 'string ' })
const ArkAction = ArkAction1.or(ArkAction2)
type ArkAction = typeof ArkAction.infer

function CreateArkAction1(): Extract<ArkAction, { type: 'ACTION_1' }> {
return { type: 'ACTION_1', value: 3 }
}
errata
errata2w ago
hm, it does work
Dimava
Dimava2w ago
It's for const typeValue = type(['===', 'ACTION_1', 'ACTION_2']) i.e. for enums
errata
errata2w ago
yeah i basically have an enum though, right?
Dimava
Dimava2w ago
No A enum of let a = {}, b = [] is [a, b].includes(v), not [{}, []].includes(v) as different object instances are not equal
errata
errata2w ago
ahh ahhh right === ok got it
Dimava
Dimava2w ago
So you are checking if your object is one of two ArkType instances lol
errata
errata2w ago
ahhh ok ok, thank you that makes sense
Dimava
Dimava2w ago
BTW how do you think it should be named? The make union one and the make array of values one? I do not feel like it's named perfectly so what would you guess they are named if you never used ArkType? May be more then one variant May be inspired by other validators
errata
errata2w ago
enumerated is ok, that's actually how I assumed it worked previously and .or is fine as well totally though I'm not keen on the chaining
Dimava
Dimava2w ago
@ssalbdivad we need type.oneOf or type.discriminatedUnion equivalent as I expect peoples to want a way to avoid .or chaining
errata
errata2w ago
type.union?
Want results from more Discord servers?
Add your server