1

I'm converting a project from JS to TS, and a little stuck on the following object:

let campaigns = {
  TOTAL: {
    cost: 3,
    revenue: 6,
    year: 2020,
  },
  campaignId_1: {
    name: "campaignName1",
    cost: 1,
    revenue: 4,
    video: "video1",
  },
  campaignId_2: {
    name: "campaignName2",
    cast: 2,
    revenue: 2,
    video: "video2",
  }
}

In Typescript, I want the object to ALWAYS have the "TOTAL" key with type-A value, and the rest of the keys are dynamic, and should have type-B value.

So first I've defined the child types:

type type_A = {  
  cost: number,
  revenue: number,
  year: number,
}
type type_B = {
  name: string,
  cast: number,
  revenue: number,
  video: string,
}

And now I'm trying to create a type for the parent Campaigns object:

Try 1:

type ICampaigns = {
  TOTAL: type_A,
  [key: string]: type_B, // Hoping it will be handled as "default" or "for all other non-defined keys"
}

But got the following error message: Property 'TOTAL' of type 'type_A' is not assignable to string index type 'type_B'.(2411).

Try 2:

type ICampaigns =  {
  TOTAL: type_A,
} & {
  [key: string]: type_B, // Hoping it will be handled as "default" or "for all other non-defined keys"
}

And now it compiles, but when trying to define such instance I'm getting errors no matter if TOTAL is of type_A or type_B.

let campaigns: ICampaigns = {
  TOTAL: {
    cost: 3,
    revenue: 6,
    year: 2020,
  },
  campaignId_1: {
    name: "campaignName1",
    cost: 1,
    revenue: 4,
    video: "video1",
  },
  campaignId_2: {
    name: "campaignName2",
    cost: 2,
    revenue: 2,
    video: "video2",
  }
}

I know that doing type_A|type_B will solve my problem, but then the TOTAL key will be able to have the type_B object as value, and other dynamic keys can have type_A values, which is not good.

I also know I can convert the Campaigns object to have only defined keys:

let campaigns: ICampaigns = {
  TOTAL: {
    cost: 3,
    revenue: 6,
    year: 2020,
  },
  campaignDetails: { // <--- change
    campaignId_1: {
      name: "campaignName1",
      cost: 1,
      revenue: 4,
      video: "video1",
    },
    campaignId_2: {
      name: "campaignName2",
      cost: 2,
      revenue: 2,
      video: "video2",
    }
  }
}

But that's a lot of converting to do in my project, and also feels like giving up...

1
  • TL;DR version - the following don't work: type ICampaigns = { defined_required_value: string, [all_other_keys: string]: number, } or type ICampaigns = { defined_required_value: string, } & { [all_other_keys: string]: number, } Commented Aug 7, 2020 at 11:44

1 Answer 1

1

This happens because TOTAL also matches the definition of [key: string]: type_B, but this solution should work for you

Sign up to request clarification or add additional context in comments.

1 Comment

The second answer there (a more specific link) does work! Thx! (The accepted answer doesn't work)

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.