1

In TypeScript, function Array.Prototype.includes requires me to pass in the same type as in the original array. But I'm thinking isn't the whole point of using includes to find out if a key of arbitrary string type exists in an array with known type?

Consider code below:

type CONFIG_MODEL = {
  URL: string;
  Protocol: string;
  Port: number;
  Encrypted: boolean;
}

const ALLOWED_KEYS: (keyof CONFIG_MODEL)[] = ['URL', 'Protocol'];

function setup(configs: { [key: string]: string }) {
  Object.keys(configs).forEach(configKey => {
    if (ALLOWED_KEYS.includes(configKey)) {
      // do something
    }
  })
}

Link to TypeScript Playground

TypeScript throws me an error when using includes, stating:

Argument of type 'string' is not assignable to parameter of type 'keyof CONFIG_MODEL'

Thanks!

2

2 Answers 2

1

Just try to iterate over allowed keys instead of whole object keys Example:

type CONFIG_MODEL = {
  URL: string;
  Protocol: string;
  Port: number;
  Encrypted: boolean;
}

type AllowedKeys = Array<keyof CONFIG_MODEL>;

const ALLOWED_KEYS: AllowedKeys = ['URL', 'Protocol'];

const hasProperty=<Obj,Prop extends string>(obj:Obj,prop:Prop):obj is Obj & Record<Prop,string>=>
  Object.prototype.hasOwnProperty.call(obj,prop);

function setup(configs: { [key: string]: string }) {  
  ALLOWED_KEYS.forEach(elem=>{
    if(hasProperty(configs, elem)){
      // do smth with config
      const result = configs[elem] // ok
    }
  })
}
Sign up to request clarification or add additional context in comments.

2 Comments

I believe type casting here is a bad choice. It deadens all the benefits I get from using TypeScript. I KNOW the input configs is NOT of type AllowdKeys, so I believe casting it, misleads other developers.
Thanks @captain-yossarian. That's a nice workaround. :thumbsup:
0

The as string[] cast in the penultimate line here, just before .includes, also addresses the issue:

//type externally defined in original
type ClassicalElement = 'earth' | 'water' | 'wind' | 'fire'; 
const classicalElements = ['earth', 'water', 'wind', 'fire'] as ClassicalElement[];
const isClassicalElement = function(
    possibleElement: string
): possibleElement is ClassicalElement {
    return (classicalElements as string[]).includes(possibleElement);
}

Playground links: with and without error.

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.