103

I've been going through and trying to convert existing projects (from Node.js) to TypeScript.

For context, I'm using the http-status package (https://www.npmjs.com/package/http-status)

I'm trying to pass variables through into their default export, but it's getting an error:

import status = require("http-status");

status.OK; // this works
status["OK"] // this also works

let str = "OK";
status[str]; // error

Error:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'HttpStatus'.
No index signature with a parameter of type 'string' was found on type 'HttpStatus'.


How would I convert this usage to TypeScript?

0

5 Answers 5

147

"OK" is a string, and str is implicitly taking the type string in your code.

When you try to access an object's property, you need to use a type keyof. TypeScript then knows you are not assigning a random string; you are assigning strings compatible with the properties (keys) for the object.

Also, since status is a variable, not a type, you need to extract its type with typeof.

Try:

let str = "OK" as keyof typeof status;
status[str]; // 200

or more cleanly:

type StatusKey = keyof typeof status;
let str: StatusKey = "OK";
status[str]; // 200

// and to answer the question about reversal
status[status.OK as StatusKey]; // OK

See: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#keyof-and-lookup-types

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

6 Comments

Thanks, though I'm getting further issues. status.OK returns a number of 200, however a string of "200" exists as a key on the status object. How would I convert one to the other? So the function (due to your answer) is correctly requiring a string of 200, doing String(status.OK) doesn't seem to satisfy this.
@GuillaumeF. thanks to your answer, I was able to resolve a blocker that was bugging me for the last 3-4 days!! Thanks a lot!
const str = "OK"; Is easiest & most readable
in the case where you want to use 'this', the syntax is: "let str = "OK" as keyof this;" No need for typeof when using this. This was my use case to reduce writing lots of duplicate code
Lots of searching and this was what I needed. Loving TS more and more every day. Although this is a bit verbose, I know why it needs to be. Still awesome. Thank you
|
12
const obj = {
  name: 'Bobby Hadz',
  country: 'Chile',
};

// 👇️ type ObjectKey = "name" | "country"
type ObjectKey = keyof typeof obj;

const myVar = 'name' as ObjectKey;

console.log(obj[myVar]); // 👉️ Bobby Hadz

Comments

9

I had to access second level dynamic key from an object.

const myObj = {
  "address": {
    "street": "Main ave",
    "city": "NYC"
  }
}

secondLevelDynamic(field: string) {

  let dynamicKey = field as keyof myObj;

  let myProp = this.myObj['address'];
  let myDynamicPropValue = myProp[dynamciKey]
}

Comments

3

Actually there's a simpler fix, you just have to just use const assertion.

Here's the fix:

const str = "OK" as const; // <-- add "as const", now `str` has type of "OK" instead of `string`
status[str]; // No more error!

Playground link.

1 Comment

const str = "OK" is a more elegant way to write this. If OP asked how to do it with a dynamic variable, he probably won't want a constant.
2

I came across the same problem when I wanted to implement an express patch request on a resource. I wanted to parse through the request body and update only which are specified in the body.

Following is the demo code which I found to be working by using TypeScript Generics.

interface ObjType {
  name: string,
  addr: string
}

const demo: ObjType = {
  name: "Foo",
  addr: "Bar"
}

const keyList: Array<keyof ObjType> = ["name", "addr"]

const keyListFromObject: Array<keyof ObjType> = Object.keys({ name: "John", addr: "Alexandria" }) as Array<keyof ObjType>
keyList.forEach((el) => console.log(demo[el]))

keyListFromObject.forEach((el) => console.log(demo[el]))

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.