Reputation: 74909
Given an object, I would like to create a second typed object that has a subset of the first's keys and different value types. I tried Partial<keyof ...>
but that seems to have no effect. Is there some other way I can type the second object (mapping
in the example below).
Example: (on TypeScript Playground)
const obj = {
a: '1',
b: '2',
c: 3,
d: 4,
e: false,
f: 'Hmmm',
};
// Below gives error:
// Type '{ a: number; b: number; }' is missing the following properties from type 'Record<"a" | "b" | "c" | "d" | "e" | "f", number>': c, d, e, f(2739)
const mapping: Record<keyof typeof obj, number> = {
a: 10,
b: 20
};
// basically same error using Partial<>
// Type '{ a: number; b: number; }' is missing the following properties from type 'Record<Partial<"a" | "b" | "c" | "d" | "e" | "f">, number>': c, d, e, f(2739)
const mapping2: Record<Partial<keyof typeof obj>, number> = {
a: 10,
b: 20
};
// basically same error using Partial<> a little differently
// Type '{ a: number; b: number; }' is missing the following properties from type 'Record<Partial<"a" | "b" | "c" | "d" | "e" | "f">, number>': c, d, e, f(2739)
const mapping3: Record<keyof Partial<typeof obj>, number> = {
a: 10,
b: 20
};
Upvotes: 4
Views: 3556
Reputation: 3297
You are close..
const obj = {
a: '1',
b: '2',
c: 3,
d: 4,
e: false,
f: 'Hmmm',
};
const mapping: Partial<Record<keyof typeof obj, number>> = {
a: 10,
b: 20
};
// or
const mapping2: { [K in keyof typeof obj]?: number }= {
a: 10,
b: 20
};
Upvotes: 1
Reputation: 134881
Partial<>
only marks all properties of a type as optional. I think what you're looking for is a modification of Pick<>
which creates a new type with a subset of properties of another type.
Though, the types of the properties that were picked are preserved, you'll need to map them to new types.
You can create the type for this:
type PickNumber<Type, Keys extends keyof Type> = {
[K in Keys]: number;
};
const value: PickNumber<typeof obj, 'a' | 'b'> = {
a: 1, // ok
b: '2', // bad type
c: 3, // invalid property
};
With that said, what you're trying to get is a subset of the set of keys for a type. You can get the subset of a union of types using Extract<>
.
Pick<>
does this for you already but this is equivalent:
type PickAlt<Type, Keys> = {
[K in Extract<keyof Type, Keys>]: Type[K];
};
So applying Extract<>
here but inlined:
const value: {[K in Extract<keyof typeof obj, 'a' | 'b'>]: number} = ...;
Or in terms of the Record<>
type:
const value: Record<Extract<keyof typeof obj, 'a' | 'b'>, number> = ...;
Upvotes: 1
Reputation: 214957
You can create the type without using Partial
, since Partial
doesn't really change the value type as you needed here:
const mapping: { [K in keyof typeof obj]?: number }= {
a: 10,
b: 20
};
Upvotes: 5