-
Notifications
You must be signed in to change notification settings - Fork 328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[discussion] something similar to TS Pick<T> #300
Comments
You can use a "standard" declare function pick<O, K extends keyof O>(o: O, keys: Array<K>): Pick<O, K>
const BarT = t.type(pick(FooT.props, ['a'])) |
Indeed. 2 points though:
Hence why I started this discussion: given |
I also don't think that that solution works for intersection codecs, as far as I can tell. |
|
Ah, makes sense. That said, it seems kinda silly that I'd have to know the inner implementation of |
You don't have to, but you need to understand what an intersection type is. Then you can better reason about why it is the way it is. An intersection does not have to consist only of object like types. const A = t.intersection([t.string, t.type({ bar: t.number })]) so without the extra layer of |
except to execute a |
As for many open source projects the documentation is suboptimal, but |
@mlegenhausen is it my original post still discussed? I'm not sure I understand how intersection has anything to do with |
@zerkms it is related because you can define new interface like types with an intersection, that combine multiple |
@mlegenhausen I'm not sure I'm following: With intersection-based solution you must declare both types of the keys and the values. That's the significant difference: I'd rather infer the value than have to declare it manually. |
@zerkms this is valid typescript type X = Pick<{ foo: number } & { bar?: string }, “bar”> With a pick function, I assume this should work: const x = pick(intersection([type({ foo: number }), partial({ bar: string })]), [“bar”]); because it’s analogous TypeScript to io-ts code. |
@osdiab would it accept |
Ah I see what you’re saying, but I feel fairly confident it’s possible for it to be inferred with a recursive type. EDIT: working version at #300 (comment) type KeyOfCodec<Codec extends Any> =
Codec extends Intersection ?
KeyOfCodecs<Codec[“types”]>
: Codec extends Type ?
keyof Codec[“props”]
: something // other cases
// not sure if this is constructed correctly,
// if a fully recursive variadic type can’t
// work properly then it can at least be
// manually specified for a reasonable
// number of array lengths
type KeyOfCodecs<Array extends Any[]> =
Array extends [Head, ...Tail] ?
KeyOfCodec<infer Head> | KeyOfCodecs<infer Tail>
: never |
Ah for the array this would be relevant? |
This seems to work when I tried it out on my machine for inferring the keys properly, Typescript 3.7.2: type Head<T extends any[]> = T extends [any, ...any[]] ? T[0] : never;
type Tail<T extends any[]> =
((...args: T) => never) extends ((a: any, ...args: infer R) => never)
? R
: never
export type KeysOfCodecs<Codecs extends Mixed[]> = {
recurse: KeyOfCodec<Head<Codecs>> | KeysOfCodecs<Tail<Codecs>>
end: never
}[Codecs extends [Mixed, ...Mixed[]] ? "recurse" : "end"];
export type KeyOfCodec<Codec extends Mixed> =
Codec extends IntersectionC<infer Codecs>
? KeysOfCodecs<Codecs>
: Codec extends TypeC<infer TypeProps>
? keyof TypeProps
: Codec extends PartialC<infer PartialProps>
? keyof PartialProps
: never;
export function pick<Codec extends Mixed, Keys extends KeyOfCodec<Codec>>(
codec: Codec,
keys: Keys[]
): PickCodec<Codec, Keys> { // PickCodec not implemented yet
throw new Error("not yet implemented")
} Not sure how stable that is for TypeScript versions, as the inference of tuples is definitely a feature in flux in TypeScript, wouldn't work for old TypeScript versions for sure |
@gcanti Is the canonical solution still to use a generic pick, or is io-ts going to provide an implementation at some point? Thanks! |
@VanTanev No, I don't think so |
@gcanti How about adding it to the non-core package io-ts-types? |
@ivawzh I'm not against that, however if the solution is not implementable using the new experimental modules, it's not going to last |
For folks looking to make this work only for a simple export function pick<P extends t.Props, K extends keyof P>(
Model: t.TypeC<P>,
keys: K[],
): t.TypeC<Pick<P, K>> {
const pickedProps = {} as Pick<P, K>;
keys.forEach(key => {
pickedProps[key] = Model.props[key];
});
return t.type(pickedProps);
} Usage: const PickedModel = pick(Model, ["id", "name"]);
type PickedModel = t.TypeOf<typeof PickedModel>; |
And to complement's @mDibyo pick, this works for export function omit<P extends t.Props, K extends keyof P>(
Model: t.TypeC<P>,
keys: K[],
): t.TypeC<Pick<P, Exclude<keyof P, K>>> {
const allKeys = Object.keys(Model) as K[];
const keesToKeep = allKeys.filter((x) => !keys.includes(x)) as Exclude<
typeof allKeys,
typeof keys
>;
return pick(Model, keesToKeep);
} |
First, I really appreciate the work on this library. It's pretty epic. I've been evaluating io-ts, and I saw this compatibility chart which made me happy that this was tracking feature parity with TypeScript. |
@mDibyo Thanks for the Noob question: I couldn't use the same |
Not at all a noob question @sagarchk - I was trying to figure out the same thing. 😆 Yeah exactly, the For this and other reasons, we have stopped using EDIT: Thinking more about this, making
Someone just has to implement it. 😆 |
Curious what you do as an alternative? Custom intersection implementation?
On Thu, Feb 25, 2021 at 0:16 Dibyo Majumdar ***@***.***> wrote:
Not at all a noob question @sagarchk <https://github.com/sagarchk> - I
struggled with the same thing. 😆
Yeah exactly, the pick function will only work with TypeC currently. As
far as I can tell, making pick work with t.intersection is pretty hard,
and will best be implemented at the library level. There's some discussion
about this earlier in this Issue if you're interested in learning more.
For this and other reasons, we have stopped using t.intersection in the
project we are working on.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#300 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAONU3WWZOGZUD6XYAXJEB3TAUJ4NANCNFSM4G3WS4FA>
.
--
Omar
|
@osdiab Just saw your response. We haven't found a need to use And once the data is typed, we can always just use Typescript intersections. |
Full example using implementations above: import * as t from "io-ts"
export function pick<P extends t.Props, K extends keyof P>(
Model: t.TypeC<P>,
keys: K[]
): t.TypeC<Pick<P, K>> {
const pickedProps = {} as Pick<P, K>
keys.forEach((key) => {
pickedProps[key] = Model.props[key]
})
return t.type(pickedProps)
}
export function omit<P extends t.Props, K extends keyof P>(
Model: t.TypeC<P>,
keys: K[]
): t.TypeC<Pick<P, Exclude<keyof P, K>>> {
const allKeys = Object.keys(Model.props) as K[]
const keysToKeep = allKeys.filter((x) => !keys.includes(x)) as Exclude<
typeof allKeys,
typeof keys
>
return pick(Model, keysToKeep)
} |
There is a TC39 proposal for adding basic |
Do you want to request a feature or report a bug?
A feature
With typescript it's possible to have
Is it technically possible to have something similar in
io-ts
that looks like?
The text was updated successfully, but these errors were encountered: