3

Could someone explains why in the example code below typescript gives the error message "const key: string Argument of type 'string' is not assignable to parameter of type 'keyof Condition"

interface Condition {
    GOOD: 'GOOD';
    BAD: 'BAD';
    NONE: 'NONE';
}

const ObjWithAllCondition: Condition = {
    GOOD: 'GOOD',
    BAD: 'BAD',
    NONE: 'NONE',
};

interface Result {
    condition: keyof Condition;
    count: number;
}

const getKeyValue = <T extends Condition, K extends keyof T>(obj: T, key: K) => obj[key];

const getResult = (): Result[] => {
    const result = [];
    for (const key in ObjWithAllCondition) {
        result.push({
            condition: getKeyValue(ObjWithAllCondition, key), // this is error
            count: 1,
        });
    }

    return result;
};

1 Answer 1

4

Because TypeScript uses a structural type system, all objects can have extra properties beyond what exists in its defined type (and the compiler is ok with this as long as the properties that are known are assignable to the type of the object).

Because of this, using the in operator or methods which iterate an object's keys might return values which are not in the type that you're expecting, so all of those keys/properties are of the type string (for type safety).

You can refactor your example to derive the properties in your Condition type from an array of the possible keys, and then use that array when iterating the keys. Here's an example:

TS Playground

const conditions = ['GOOD', 'BAD', 'NONE'] as const;
type ConditionName = typeof conditions[number];

type StringUnionToKV<S extends string> = { [K in S]: K };

type Condition = StringUnionToKV<ConditionName>;

const obj: Condition = {
  GOOD: 'GOOD',
  BAD: 'BAD',
  NONE: 'NONE',
};

type Result = {
  condition: ConditionName;
  count: number;
};

const getKeyValue = <T extends Condition, K extends keyof T>(obj: T, key: K) => obj[key];

const getResult = (): Result[] => {
  const result = [];

  for (const key of conditions) {
    result.push({
      condition: getKeyValue(obj, key),
      count: 1,
    });
  }

  return result;
};

If you are going to be working with a fixed set of strings, you might also be interested in string enums.

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

1 Comment

Thanks, yes I tried using enum but had had the same issue and decided to use object

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.