Closed ghost closed 6 years ago
You can use existing Partial
and Exclude
to implement an approach like this:
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
type WithOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
interface Foo {
foo: string;
bar: number;
baz: boolean;
}
// { foo?: string; bar: number; baz?: boolean; }
type OptionalFoo = WithOptional<Foo, 'foo' | 'baz'>;
const createFoo = (base: OptionalFoo): Foo => {
return { foo: 'foo', baz: true, ...base };
};
const optionalFoo: OptionalFoo = { foo: '???', bar: 2 };
const fullFoo = createFoo(optionalFoo); // { foo: '???', bar: 2, baz: true }
@0x414c
thanks anyway, I hope Omit
and WithOptional
can be added to lib.d.ts in the future cause it's really a very common need.
yet there's another problem with keyof a Union type
interface MessageA {
mid: number;
type: number;
text: string;
}
interface MessageB {
mid: number;
type: number;
url: string;
}
type Message = MessageA | MessageB
type Keys = keyof Message // 'mid' | 'type'
/**
* {
* mid?: number;
* type: number;
* }
*/
type OptionalMessage = WithOptional<Message, 'mid'>
// what I really what :
type OptionalMessageNeed = WithOptional<MessageA, 'mid'> | WithOptional<MessageB, 'mid'>
I just got a solution.
type AllKeyOf<T> = T extends never ? never : keyof T
type Omit<T, K> = { [P in Exclude<keyof T, K>]: T[P] }
type Optional<T, K> = { [P in Extract<keyof T, K>]?: T[P] }
type WithOptional<T, K extends AllKeyOf<T>> = T extends never ? never : Omit<T, K> & Optional<T, K>
/**
{
mid?: number;
type: number;
text?: string;
}
| {
mid?: number;
type: number;
url: string;
}
*/
type a = WithOptional<Message, 'mid' | 'text'>
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.
Guys those solutions are unredable. I think it's better to create separate interface.
This works for me
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<T>;
This is really good. However, is there a way to keep the keys ordered as the original type?
type-fest
has SetOptional
, for those who would rather npm install --dev
utilities like this.
@rattrayalex Thank you! This has all that I could need and more
type onlyOneRequired = Partial<Tag> & {id: string}
In the above type all properties of Tag are optional instead id
which is required.
Edited on 2023-09-06:
The PartialWithRequired
present here will not convert property declared as optional (like daz?: string
) as required. In case is what you need use the great code of @techieshark of this comment
In case you need to ensurethat All prop are optional but some of those are required
this worked for me (Thanks to @gr2m for the starting point.)
// All props are required but some are optional
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<T>;
type Test = {
foo: string;
bar: string;
baz: string;
daz?: string;
};
type Test1 = Optional<Test, "foo">;
const test1: Test1 = {
bar: '',
baz: ''
}
type Test2 = Optional<Test, "bar" | "baz">;
const test2: Test2 = {
foo: ''
}
// All prop are optional but some of those are required
type PartialWithRequired<T, K extends keyof T> = Pick<T, K> & Partial<T>;
type Test3 = PartialWithRequired<Test, 'bar' | 'foo'>;
const test3:Test3 = {
bar: '',
foo: ''
}
@tresorama thanks for that starting point. It seems that since type Test
already requires all properties but one (daz?
), the code provided works.
But if starting out with optional properties and we want to actually make them required, we can also use the Required<> utility. Here's this:
type Test = {
foo?: string;
bar?: string;
baz: string;
};
// All prop are optional but some of those are required -- NOTE! doesn't work, see Test1.
type PartialWithRequired<T, K extends keyof T> = Pick<T, K> & Partial<T>;
type Test1 = PartialWithRequired<Test, 'foo'|'bar'>;
// @ts-expect-error since `Pick` from `PartialWithRequired` does NOT mark an optional parameter like 'foo' or 'bar' as required
const test1:Test1 = {}
// Actually works:
type PartialExceptTheseRequired<T, K extends keyof T> = Pick<Required<T>, K> & Partial<T>
type Test2 = PartialExceptTheseRequired<Test, 'foo'|'bar'>
const test2:Test2 = {}
// ^ it errors, which we want, since we are now requiring foo and bar but haven't set them.
@techieshark Fantastic!
I didn't know Required
Search Terms
Suggestion
Use Cases
current
Partial<T>
will make all properties ofT
optional I want to specify only some properties ofT
optionalExamples
it's very often sometimes we want to omit some properties of an object and later supplement it. currently typescript has concepts like
Intersection
、Union
, how aboutComplement
?Checklist
My suggestion meets these guidelines: