6

After some typescript studying and asking around i come up with the following shared object types declaration for multiple properties.

  • Question 1: is there simplier way to do it for multiple props wih shared types?
  • Question 2: how to resolve last two examples?

Typescript playground

type StringProps = 'name' | 'surname' | 'color'
type NumberProps = 'age' | 'height'

//Simple type
type Simple = { [key in StringProps]: string };
const obj1: Simple = {
    name: 'Agent',
    surname: 'Smith',
    color: 'red'
}

//Optional type
type Optional = { [key in StringProps]?: string };
const obj2: Optional = {
    name: 'Agent'
}

//Combined optional type
type Combined = { [key in NumberProps]?: number } & Optional;
const obj3: Combined = {
    name: 'Alex',
    height: 2
}

// Property type change
type StringColor = Partial<Record<Exclude<NumberProps, 'color'>, number> & { color?: string }>
const obj4: StringColor = {
    color: 'rgb'
}

// How to add any additional props with unknown keys?
type Additional = { [key: string]: boolean };
const obj5: Optional & Additional = {
   color: 'rgb',
   additional: true
}

// How to exclude Y prop from a type like this?
type XY = { x: string, y: number };
const obj6: XY = {
   x: 'abc',
   y: 1
}

type X = Record<Exclude<XY, 'y'>, number>
const obj7: XY = {
   x: 'abc'
}

3 Answers 3

4

I think you can clean this up a bit.

First make Records and then modify them, if you need the keys you can always call keyof on the type

type Simple = Record<'name' | 'surname' | 'color', string>
type Numbers = Record<'age' | 'height', number>

// if you need the keys
type SimpleKeys = keyof Simple // "name" | "surname" | "color"
type NumbersKeys = keyof Numbers // "age" | "height"

//Simple type
const obj1: Simple = {
    name: 'Agent',
    surname: 'Smith',
    color: 'red'
}

//Optional type
type Optional = Partial<Simple>
const obj2: Optional = {
    name: 'Agent'
}

//Combined optional type
type Combined = Partial<Numbers & Simple>;
const obj3: Combined = {
    name: 'Alex',
    height: 2
}

// Property type change
type StringColor = Partial<Omit<Simple, 'color'> & { color?: string }>
const obj4: StringColor = {
    color: 'rgb'
}

// How to exclude Y prop from a type like this?
type XY = { x: string, y: number };
// Pick<XY, 'x'> or Omit<XY, 'y'>
const obj6: Pick<XY, 'x'> = {
   x: 'abc',
}
Sign up to request clarification or add additional context in comments.

Comments

3

Question 1:

The types look fine. You could switch it around by first creating the interfaces and then using keyof, but that is a matter of taste.

Question 2

obj5:

For obj5, you will most likely have to change the index signature of the object to any, as all declared, specific properties have to conform to the index signature.

type Additional = { [key: string]: any };
const obj5: Optional & Additional = {
   color: 'rgb',
   additional: true
}

Alternatively, you can handle this with a bit of typecasting, as you are allowed to declare this type. But you are not allowed to create it. Thus, you can typecast the created object to any and then back to the correct type like this:

type Additional = { [key: string]: boolean };
const obj5: Optional & Additional = {
   color: 'rgb',
   additional: true
} as any as Optional & Additional;

I gave a more detailed explanation on exactly this topic in another Stackoverflow Question.

obj6:

For obj6 you can simply use the Omit helper like this:

type XY = { x: string, y: number };
const obj6: XY = {
   x: 'abc',
   y: 1
}

type X = Omit<XY, "y">
const obj7: XY = {
   x: 'abc'
}

1 Comment

@RTW I added a Typesafe alternative for obj5 solution.
3

Your approach for creating the types looks good to me.

As for question two, why not use Omit to exclude the property you are not interested in? e.g.

type X = Omit<XY, "y">
const obj7: X = {
   x: 'abc'
}

As for obj5:

type Any= { [key: string]: any};
const obj5: Any = {
   color: 'rgb',
   additional: true
}

Note how I didn't use "Optional & Any" as the use of "Any" would render the inclusion of "Optional" redundant.

3 Comments

thanks, but it's more about exluding few props from multiple property object
Just use omit then: type X = Omit<XY, "y">
@pascalpuetz thanks, now only obj5 question left :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.