#Combining parts of objects in TypeScript

1 messages · Page 1 of 1 (latest)

pearl cedar
#

I'm wanting to combine two objects playerBio and playerStats to create playerDetail. I was thinking I could use a spread operator to accomplish this, but I'm not wanting all of the params from playerStats. Is there a good way to accomplish this?

errant galleon
#

Then you can combine what you get.

#

Here's how it would look, and note that I'm guessing on the shape of your types.

#
type PlayerBio = {
  id: string;
  name: string;
  team: string;
}

// Note how playerId is used here and would reference a PlayerBio
type PlayerStats = {
  id: string;
  playerId: string;
  wins: number;
  losses: number;
  draws: number;
}

// This takes the PlayerBio type and joins it with the modified PlayerStats type.
// The Omit utility strips out the types that aren't needed in both places
// In this case, 'id' would be duplicated and 'playerId' is not needed
type PlayerDetail = PlayerBio & Omit<PlayerStats, "id" | "playerId">;

// This object has all properties of the PlayerDetail type
const player: PlayerDetail = {
  id: "abc123",
  name: "Joe Player",
  team: "Joe's Team",
  wins: 4,
  losses: 2,
  draws: 0
}
pearl cedar
#

This makes sense for the most part. How do I parse this into JSON? I feel like I'm missing a step to get it to output all the playerDetails

pearl cedar
#

I may be asking the question wrong, or not understanding. I have an index.ts file that contains the following two types

  fullName: string;
  shortName: string;
  position: string;
  playerId: number;
  imgId: number;
  orgId: number;
  orgAbbr: string;
  teamAbbr: string;
};

export type PlayerStatsDTO = {
  playerId: number;
  serviceTime: number;
  g: number;
  gs: number;
  ip: number;
  h: number;
  hr: number;
  bb: number;
  k: number;
  np: number;
  era: number;
  fip: number;
  hPer9: number;
  hrPer9: number;
  bbPer9: number;
  kPer9: number;
  walkRate: number;
  kRate: number;
  gbRate: number;
};```

From there I have a `playerStats.ts` and a `playerBios.ts` files that have similar text to the following

```import { PlayerBioDTO } from "../types";

export const playerBios: PlayerBioDTO[] = [
  {
    fullName: "Burke, Trevor",
    shortName: "Burke T.",
    position: "RHS",
    playerId: 123456,
    imgId: 621057,
    orgId: 1,
    orgAbbr: "TBD",
    teamAbbr: "TBD",
  },```

I want to create a `PlayerDetailDTO` type (which I think I accomplished with the above `Omit`. What I'm missing is pulling the data from the `playerStats.ts` and `playerBios.ts` to create the `playerDetails.ts` file. If I do a spread operator to try and combine, it just console logs the bio and stats separately. Thoughts?
errant galleon
#

OK, so there's a couple things at play here. First, keep in mind that Typescript is only checking things at compile time, so you will need to do a runtime transform to get the actual data into the proper shape. (which I think you are trying to do) That said, you can address the typescript shapes first. The example I have used Omit<T, keys> but you can use Pick<T, keys> if you have less keys you want to keep than the keys you want to omit. Then in the line type PlayerDetail = PlayerBio & Omit<PlayerStats, "id" | "playerId">;, the & symbol merges the two types into one. That gives you your final shape.

#

By trying to use the spread operator you are trying to put all the keys from both objects into it, and Typescript should yell at you for that. You can work around that in a couple of ways.

  1. You destructure the keys you need from your runtime JS from each type, then apply them to the Detail object. This is the simplest in theory but also requires you to manually maintain it with less assistance from typescript.
const { fullName, shortName, playerId } = someBioDtoObject;
const { serviceTime, g, gs } = someStatsDtoObject;

const detailDto: PlayerDetailDTO = {
  fullName, 
  shortName,
  playerId,
  serviceTime,
  g,
  gs,
}
#

You can see that gets unwieldy though, so there is another option if you want to jump a bit farther down the rabbit hole.

#

Zod will allow you to build validators that will take what you put in to them, and strip out any keys it doesn't have a validator set up for. What toZod does is give you a way to leverage typescript to enforce that your zod validator matches a typescript type shape for it's output, thereby giving you a compile time check for compliance to a runtime shape.

#

Option 1 will totally work, and if your data shapes are static and stable it's probably the better option. You also don't need to fuss with another dependency, and learn it if you don't know it already.

#

OTOH option 2 will provide greater long term flexibility. If you change one thing feeding the types, Typescript will pick it up wherever it needs to change.

pearl cedar
#

@errant galleon thanks for all the info. I'll definitely dive back into this in a little bit. I'm probably going to do option 1. Mostly because I'm learning TS as I do this and don't want to further melt my brain by adding onto that lol.

errant galleon
#

I totally get it. Did option 1 make sense?

pearl cedar
#

It does, when reading. I'm sure in doing I'll get tripped up a little. But if I run into issues I will let you know.

pearl cedar
#

I'm missing a step somewhere and I'm drawing a blank. I have my type and everything set up from option 1. But I'm having an issue getting it all to compile the player details together to put it in my playerDetails.ts file.

errant galleon
#

@pearl cedar Do you have this in a GH repo you can share? If so, push your latest changes and send me a link.

errant galleon
pearl cedar
#

It's in a codesandbox, would you be up for a call I can screenshare

errant galleon
#

got people in and out of my office like crazy 😂 call probably won't work. Share your related code here if that's OK, I'll be popping in and out.

pearl cedar
#

haha I get it. I'll do so in a few

errant galleon