Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I want to be able to assign an object property to a value given a key and value as inputs yet still be able to determine the type of the value. It's a bit hard to explain so this code should reveal the problem:
type JWT = { id: string, token: string, expire: Date };
const obj: JWT = { id: 'abc123', token: 'tk01', expire: new Date(2018, 2, 14) };
function print(key: keyof JWT) {
switch (key) {
case 'id':
case 'token':
console.log(obj[key].toUpperCase());
break;
case 'expire':
console.log(obj[key].toISOString());
break;
function onChange(key: keyof JWT, value: any) {
switch (key) {
case 'id':
case 'token':
obj[key] = value + ' (assigned)';
break;
case 'expire':
obj[key] = value;
break;
print('id');
print('expire');
onChange('id', 'def456');
onChange('expire', new Date(2018, 3, 14));
print('id');
print('expire');
onChange('expire', 1337); // should fail here at compile time
print('expire'); // actually fails here at run time
I tried changing value: any to value: valueof JWT but that didn't work.
Ideally, onChange('expire', 1337) would fail because 1337 is not a Date type.
How can I change value: any to be the value of the given key?
–
UPDATE: Looks like the question title attracts people looking for a union of all possible property value types, analogous to the way keyof gives you the union of all possible property key types. Let's help those people first. You can make a ValueOf analogous to keyof, by using indexed access types with keyof T as the key, like so:
type ValueOf<T> = T[keyof T];
which gives you
type Foo = { a: string, b: number };
type ValueOfFoo = ValueOf<Foo>; // string | number
For the question as stated, you can use individual keys, narrower than keyof T, to extract just the value type you care about:
type sameAsString = Foo['a']; // look up a in Foo
type sameAsNumber = Foo['b']; // look up b in Foo
In order to make sure that the key/value pair "match up" properly in a function, you should use generics as well as indexed access types, like this:
declare function onChange<K extends keyof JWT>(key: K, value: JWT[K]): void;
onChange('id', 'def456'); // okay
onChange('expire', new Date(2018, 3, 14)); // okay
onChange('expire', 1337); // error. 1337 not assignable to Date
The idea is that the key parameter allows the compiler to infer the generic K parameter. Then it requires that value matches JWT[K], the indexed access type you need.
–
–
–
–
There is another way to extract the union type of the object:
const myObj = { a: 1, b: 'some_string' } as const;
type values = typeof myObj[keyof typeof myObj];
Result: 1 | "some_string"
–
–
–
If anyone still looks for implementation of valueof for any purposes, this is a one I came up with:
type valueof<T> = T[keyof T]
Usage:
type actions = {
type: 'Reset'
data: number
type: 'Apply'
data: string
type actionValues = valueof<actions>
Works as expected :) Returns an Union of all possible types
With the function below you can limit the value to be the one for that particular key.
function setAttribute<T extends Object, U extends keyof T>(obj: T, key: U, value: T[U]) {
obj[key] = value;
Example
interface Pet {
name: string;
age: number;
const dog: Pet = { name: 'firulais', age: 8 };
setAttribute(dog, 'name', 'peluche') <-- Works
setAttribute(dog, 'name', 100) <-- Error (number is not string)
setAttribute(dog, 'age', 2) <-- Works
setAttribute(dog, 'lastname', '') <-- Error (lastname is not a property)
// type TEST1 = boolean | 42 | "heyhey"
type TEST1 = ValueOf<{ foo: 42, sort: 'heyhey', bool: boolean }>
// type TEST2 = 1 | 4 | 9 | "zzz..."
type TEST2 = ValueOf<[1, 4, 9, 'zzz...']>
–
You can made a Generic for your self to get the types of values, BUT, please consider the declaration of object should be declared as const, like:
export const APP_ENTITIES = {
person: 'PERSON',
page: 'PAGE',
} as const; <--- this `as const` I meant
Then the below generic will work properly:
export type ValueOf<T> = T[keyof T];
Now use it like below:
const entity: ValueOf<typeof APP_ENTITIES> = 'P...'; // ... means typing
// it refers 'PAGE' and 'PERSON' to you
Thanks the existing answers which solve the problem perfectly. Just wanted to add up a lib has included this utility type, if you prefer to import this common one.
https://github.com/piotrwitek/utility-types#valuestypet
import { ValuesType } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
// Expect: string | number | boolean
type PropsValues = ValuesType<Props>;
–
You could use help of generics to define T that is a key of JWT and value to be of type JWT[T]
function onChange<T extends keyof JWT>(key: T, value: JWT[T]);
the only problem here is in the implementation that following obj[key] = value + ' (assigned)'; will not work because it will try to assign string to string & Date. The fix here is to change index from key to token so compiler knows that the target variable type is string.
Another way to fix the issue is to use Type Guard
// IF we have such a guard defined
function isId(input: string): input is 'id' {
if(input === 'id') {
return true;
return false;
// THEN we could do an assignment in "if" block
// instead of switch and compiler knows obj[key]
// expects string value
if(isId(key)) {
obj[key] = value + ' (assigned)';
with type-fest lib, you can do that with ValueOf like that:
import type { ValueOf } from 'type-fest';
export const PATH_NAMES = {
home: '/',
users: '/users',
login: '/login',
signup: '/signup',
interface IMenu {
id: ValueOf<typeof PATH_NAMES>;
label: string;
onClick: () => void;
icon: ReactNode;
const menus: IMenu[] = [
id: PATH_NAMES.home,
label: t('common:home'),
onClick: () => dispatch(showHome()),
icon: <GroupIcon />,
id: PATH_NAMES.users,
label: t('user:users'),
onClick: () => dispatch(showUsers()),
icon: <GroupIcon />,
I realize this is slightly off topic, That said every time I've looked for a solution to this. I get sent to this post. So for those of you looking for String Literal Type generator, here you go.
This will create a string Literal list from an object type.
export type StringLiteralList<T, K extends keyof T> = T[keyof Pick<T, K>];
type DogNameType = { name: "Bob", breed: "Boxer" } | { name: "Pepper", breed: "Spaniel" } | { name: "Polly", breed: "Spaniel" };
export type DogNames = StringLiteralList<DogNameType, "name">;
// type DogNames = "Bob" | "Pepper" | "Polly";
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.