0

I'm wanting to do something like this:

type Foo = {
    name: string;
    value: any;
}

const myFoos: Foo[] = [
    {
        name: "hello",
        value: 1,
    },
    {
        name: "world",
        value: "bar"
    }
];


function createObjectFromFooArray(foos: Foo[]) : Record<string, Foo> {  //Need to change the return type
    return foos.reduce((acc, cur) => {
        return {
            ...acc,
            [cur.name]: cur
        }
    }, {});
}


const objectFoos = createObjectFromFooArray(myFoos); 

console.log(objectFoos.hello); 
console.log(objectFoos.aaa); //Should error

That is - given an array of Foos, I want to create a mapped object of Foos, and I want that object to only contain indexes that were the name property of the original Foo array . How would I do this?

1 Answer 1

1

There are a few issues here. One is you have to resist annotating myFoos as Foo[], because that makes the compiler widen the name properties to string, whereas you need to keep track of the string literal types like "hello" and "world". Instead you should use something like a const assertion to keep myFoos as narrowly-typed as possible:

const myFoos = [
  {
    name: "hello",
    value: 1,
  },
  {
    name: "world",
    value: "bar"
  }
] as const;

Then you can have createObjectFromFooArray be generic in type T of the elements of foos, where T is constrained to Foo but can be more specific. And the return type can be a conditional mapped type that iterates over the name properties of T for keys and extracts the corresponding value property for each property value:

function createObjectFromFooArray<T extends Foo>(foos: readonly T[]) {  
  return foos.reduce((acc, cur) => {
    return {
      ...acc,
      [cur.name]: cur
    }
  }, {} as { [K in T["name"]]: Extract<T, { name: K }>});
}

Which behaves as you expect:

const objectFoos = createObjectFromFooArray(myFoos);    
console.log(objectFoos.hello);
console.log(objectFoos.aaa); // error!

Okay, hope that helps; good luck!

Link to code

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.