0

I've got object with attributes in it. Each attribute has list of properties and it's value type depends on key value. I'm trying to make generic type for converting interface of attribute types to my structure

Here is example of my current code. I cannot set type for attributes.

interface IAttribute<Key, Value> {
  key: Key;
  value: Value;
  approved?: boolean;
  published?: boolean;
  fromPrototype?: boolean;
}

interface IObject<T> {
  id: string;
  attributes?: Array<IAttribute<K, T[K]>>; // K extends keyof T. How can I fix it?
}

interface ICustomAttributes {
  attr1: boolean;
  attr2: number;
}

type ICustom = IObject<ICustomAttributes>;

const o: ICustom = {
  id: "1",
  attributes: [
    {
      key: "attr1",
      value: true,
    },
    {
      key: "attr2",
      value: 123,
    },
  ],
}

Final result must looks like

type ICustomAttributes = IAttribute<"attr1", boolean> | IAttribute<"attr2", number>;

interface ICustom {
  id: string;
  attributes?: ICustomAttributes[]
}
3
  • One of the attributes is string/boolean, and the other is string/number? Commented Oct 31, 2018 at 13:06
  • key is attribute name, value is attribute value. value type depends on key. It can be any Commented Oct 31, 2018 at 13:16
  • Is your intention to allow attr1 to be added to the object multiple times? Commented Oct 31, 2018 at 13:33

1 Answer 1

1

You can convert the properties of the type to a union of IAttribute using a mapped type:

interface IAttribute<Key, Value> {
  key: Key;
  value: Value;
  approved?: boolean;
  published?: boolean;
  fromPrototype?: boolean;
}



interface IObject<T> {
  id: string;
  attributes?: Array<{ [P in keyof T]: IAttribute<P, T[P]> }[keyof T]>; // K extends keyof T. How can I fix it?
}

interface ICustomAttributes {
  attr1: boolean;
  attr2: number;
}

type ICustom = IObject<ICustomAttributes>;

const o: ICustom = {
  id: "1",
  attributes: [
    {
      key: "attr1",
      value: true,
    },
    {
      key: "attr2",
      value: 123,
    },
  ],
}

This does not however ensure that each member is present at least once and there are no duplicates. Depending on your use case this may or may not be a problem. If you need to ensure taht each member is present exactly once you are better off using an object instead of an array (you could achieve a similar effect with tuples but converting an object type to a union of all possible tuples would need to use recursive type aliases which are not recommended)

interface IObject<T> {
  id: string;
  attributes?: { [P in keyof T]: IAttribute<P, T[P]> }
}

interface ICustomAttributes {
  attr1: boolean;
  attr2: number;
}

type ICustom = IObject<ICustomAttributes>;

const o: ICustom = {
  id: "1",
  attributes: {
    "attr1": {
      key: "attr1",
      value: true,
    },
    "attr2": {
      key: "attr2",
      value: 123,
    },
  }
}
Sign up to request clarification or add additional context in comments.

Comments

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.