A
arktype•2mo ago
Dimava

Compiling scope to interfaces

I have a huge scope and I want to extract 10+ interfaces from it, preferably in a way that would compile plainly to d.ts And then remake the scope with using those interfaces
const S = scope({
foo: { a: number }
bar: { foo: foo }
})
export interface Foo = ???
export interface Bar = ??? // should be { foo: Foo }
const S = scope({
foo: { a: number }
bar: { foo: foo }
})
export interface Foo = ???
export interface Bar = ??? // should be { foo: Foo }
What the best way for that
20 Replies
ssalbdivad
ssalbdivad•2mo ago
Sounds like a huge pain. Basically duplicate all the types with the named references or create a build tool to do it
Dimava
DimavaOP•2mo ago
BTW I've tried compiling AT to d.ts and it's interesting (bad)
ssalbdivad
ssalbdivad•2mo ago
I think a build tool would be nice for sure. It's just not something TS really gives any ability to control directly (dynamically creating named references) There are some tricks you can use for unscoped typs My "e" is very stick today
Dimava
DimavaOP•2mo ago
Some of the types include whole inline scope in definition I'm currently slicing scope definitions to non-recursive parts But it causes long compilation times so I'm digging how to do it efficiently Should I ping you with some examples tomorrow? Hmm, or now when I get to PC
ssalbdivad
ssalbdivad•2mo ago
This is really something that would have to be improved in TypeScript for the most part there's nothing I can do
Dimava
DimavaOP•2mo ago
There may be some obvious api you have I missed
ssalbdivad
ssalbdivad•2mo ago
I've been talking to @Andarist a bit about this and he came up with a very clever stratgy to force standalone infrnce to expand:
const t = type({
foo: "string"
})

const inferred = t.infer

export type T = typeof inferred
const t = type({
foo: "string"
})

const inferred = t.infer

export type T = typeof inferred
With this pattern, the standalone exported type can be used even if a reference to arktype isn't resolvable
Dimava
DimavaOP•2mo ago
Yep, but I want scopes 😭
ssalbdivad
ssalbdivad•2mo ago
You may be able to make slight improvements in some cases and if you can submit PRs for them that don't negativly impact type perf/display in other cases that's fine, but 95% of the potential for improvement in these cases is in TS's hands
Dimava
DimavaOP•2mo ago
How do I infer from scopes?
ssalbdivad
ssalbdivad•2mo ago
It's totally opaque and impossible to meaningfully control what gets expanded and how when written to .d.ts files There's just not a good way to do this like I said because you can't dynamically create named references
Dimava
DimavaOP•2mo ago
Nah I mean literally like in type example above
ssalbdivad
ssalbdivad•2mo ago
I'm sure the TS team would appreciate it if 10% of the time you spent asking me for features was spent asking them to build them in a much more general and powerful way instead of me trying to hack around in a very limited way 😛 Right, but it's just not geenerally possible in TS where each scoped type is dynamically computed and I can't associate a name with it Maybe you could add a scope.declare but it will come with it's own problems in addition to being duplicative
Dimava
DimavaOP•2mo ago
You didn't get the question what's the equivalent of type(a).infer in scope({a})
ssalbdivad
ssalbdivad•2mo ago
Yeah I don't get it all the references will be dynamic you'd have to respecify every type I don't see how .infer would help or what you're asking for
Dimava
DimavaOP•2mo ago
I do have everything working already so I guess I should just show that to start
export interface Cycle extends Identity<typeof mod.Cycle.infer> { }
export interface ResourceBase extends Replace<typeof mod.ResourceBase.infer, { actcycles: Cycle[], budcycles: Cycle[] }> { }

export interface AggregateResource extends Replace<ResourceBase, Identity<typeof mod.AggregateResourceVariant.infer>> {}
export interface RegularResource extends Replace<ResourceBase, Identity<typeof mod.RegularResourceVariant.infer>> {}
export type Resource = AggregateResource | RegularResource

export interface Model extends Replace<typeof mod.Model.infer, { resources: Resource[] }> {}
export interface Cycle extends Identity<typeof mod.Cycle.infer> { }
export interface ResourceBase extends Replace<typeof mod.ResourceBase.infer, { actcycles: Cycle[], budcycles: Cycle[] }> { }

export interface AggregateResource extends Replace<ResourceBase, Identity<typeof mod.AggregateResourceVariant.infer>> {}
export interface RegularResource extends Replace<ResourceBase, Identity<typeof mod.RegularResourceVariant.infer>> {}
export type Resource = AggregateResource | RegularResource

export interface Model extends Replace<typeof mod.Model.infer, { resources: Resource[] }> {}
That's the way #1 and it did work fine
ssalbdivad
ssalbdivad•2mo ago
Right yeah that is what I'd expect but like I said you are duplicating a lot of the relationships + structures But like I said in other cases if it doesn't work, it's very unclear what I could do to change it if the inference works in .ts but not in .d.ts that is really a transformation that typescript owns not me
Dimava
DimavaOP•2mo ago
export interface $$def extends $def,
Replace<Omit<typeof $$_def, keyof ct.$def | 'g'>, {
Metric: type.cast<Metric>
Period: type.cast<Period>
Cost: type.cast<Cost>
Category: type.cast<Category>
Parameter: type.cast<Parameter>
Account: type.cast<Account>
CostCente: type.cast<CostCenter>
Project: type.cast<Project>
Service: type.cast<Service>
Vectors: type.cast<Vectors>
ABCRecord: type.cast<ABCRecord>
}> { }

type $$$_def = typeof $$$_def
export interface Cycle extends InferFace<$$$_def, 'Cycle'> { }
type $$$_def1 = Replace<typeof $$$_def, { Cycle: type.cast<Cycle> }>
export interface ResourceBase extends InferFace<$$$_def1, 'ResourceBase'> { }
export interface AggregateResource extends Replace<ResourceBase, InferFace<$$$_def1, 'AggregateResourceVariant'>> { }
export interface RegularResource extends Replace<ResourceBase, InferFace<$$$_def1, 'RegularResourceVariant'>> { }
export type Resource = AggregateResource | RegularResource

type $$$_def2 = Replace<typeof $$$_def, { Cycle: type.cast<Cycle>, Resource: type.cast<Resource> }>

export interface Model extends InferFace<$$$_def2, 'Model'> { }

export type $$$def = Replace<typeof $$$_def, { Cycle: type.cast<Cycle>, Resource: type.cast<Resource>, Model: type.cast<Model> }>
}
export interface $$def extends $def,
Replace<Omit<typeof $$_def, keyof ct.$def | 'g'>, {
Metric: type.cast<Metric>
Period: type.cast<Period>
Cost: type.cast<Cost>
Category: type.cast<Category>
Parameter: type.cast<Parameter>
Account: type.cast<Account>
CostCente: type.cast<CostCenter>
Project: type.cast<Project>
Service: type.cast<Service>
Vectors: type.cast<Vectors>
ABCRecord: type.cast<ABCRecord>
}> { }

type $$$_def = typeof $$$_def
export interface Cycle extends InferFace<$$$_def, 'Cycle'> { }
type $$$_def1 = Replace<typeof $$$_def, { Cycle: type.cast<Cycle> }>
export interface ResourceBase extends InferFace<$$$_def1, 'ResourceBase'> { }
export interface AggregateResource extends Replace<ResourceBase, InferFace<$$$_def1, 'AggregateResourceVariant'>> { }
export interface RegularResource extends Replace<ResourceBase, InferFace<$$$_def1, 'RegularResourceVariant'>> { }
export type Resource = AggregateResource | RegularResource

type $$$_def2 = Replace<typeof $$$_def, { Cycle: type.cast<Cycle>, Resource: type.cast<Resource> }>

export interface Model extends InferFace<$$$_def2, 'Model'> { }

export type $$$def = Replace<typeof $$$_def, { Cycle: type.cast<Cycle>, Resource: type.cast<Resource>, Model: type.cast<Model> }>
}
This is way #2 This is what's all that is based upon
import { scope, type } from 'arktype'
import { $def } from './brands'

export const $$_def = scope.define({
...$def,
g: '"loose"',

MetricDictionary: 'Dictionary<Metric, g>',
Metric: {
value: 'metricId',
label: 'string>0',
cats: 'Sorted<categoryId[], g>',
metricType: 'metricType',
description: 'optionalDescription',
},
import { scope, type } from 'arktype'
import { $def } from './brands'

export const $$_def = scope.define({
...$def,
g: '"loose"',

MetricDictionary: 'Dictionary<Metric, g>',
Metric: {
value: 'metricId',
label: 'string>0',
cats: 'Sorted<categoryId[], g>',
metricType: 'metricType',
description: 'optionalDescription',
},
tbh I do like the g: "loose" hack to variate the behaviour definitions work fine in d.ts but I feel like validating them 5+ times takes time Can I "clean" defintions by casting them all to type.cast<unbranded> so they don't revalidate?
ssalbdivad
ssalbdivad•2mo ago
Yeah that should work
Dimava
DimavaOP•2mo ago
Okay will do that But so, How do I cast scope({ a }) to type(a).infer? I guess that's the most sensible question I can ask
Want results from more Discord servers?
Add your server