8

I have a simple function that takes an object in parameter. In order to receive only valid data, I need to type the key of the object as such:

type DataType = "about" | "favorites" | "username";
type UpdatedData = { [key in DataType]: any };

function onSave (updatedData: UpdatedData){
//do stuff
}

// in a component
const onClickSave = () => onSave({ "about": text });

Typescript throws the following error:

Argument of type '{ about: text; }' is not assignable to parameter of type 'UpdatedData'. Type '{ about: text; }' is missing the following properties from type 'UpdatedData': favorites, username

How to fix this? Of course, I could write [key: string] instead of [key in DataType] but the typing would be useless then.

6
  • Are all the properties of UpdatedData optional?
    – yudhiesh
    Commented Feb 6, 2021 at 15:51
  • Yes, you should be able to pass one of the DataType option as the key of the object in onSave().
    – DoneDeal0
    Commented Feb 6, 2021 at 15:51
  • one and only one ? Commented Feb 6, 2021 at 15:56
  • Basically, onSave({hello: text}) should be false because the key "hello" is not allowed, and onSave({about: text}) should be true because the key "about" is allowed.
    – DoneDeal0
    Commented Feb 6, 2021 at 15:58
  • 2
    and onSave({}) or onSave({about:'', username:''}) Commented Feb 6, 2021 at 15:59

3 Answers 3

11

As the properties of UpdatedData can be optional just add in a ? to make them optional.

Edit: As @Jérémie B mentioned an empty {} is still permitted with this.

type DataType = "about" | "favorites" | "username";
type UpdatedData = { [key in DataType]?: any };
function onSave (updatedData: UpdatedData){
}
const text = "hello"

const onClickSave = () => onSave({ "about": text });
4
  • but onSave({}) is valid here. with ths function name, I don't know if it's really allowed. Commented Feb 6, 2021 at 15:55
  • @JérémieB that is true, I will ask the OP whether this is sufficient or whether {} should not be allowed.
    – yudhiesh
    Commented Feb 6, 2021 at 16:00
  • {} should not be allowed, it wouldn't make sense to send an empty object to the server.
    – DoneDeal0
    Commented Feb 6, 2021 at 16:08
  • 1
    I will accept @yudhiesh's answer, I only have to make a check before the call, this will do the trick. Thanks!
    – DoneDeal0
    Commented Feb 6, 2021 at 16:10
0

try this :

type DataType = "about" | "favorites" | "username";
type Expand<U> = U extends string ? { [key in U]: any } : never

type UpdatedData = Expand<DataType>

TS Playground

0

For what it's worth, the same thing that @JérémieB provided can be accomplished with the following const assertion:

const DataType = ["about", "favorites", "username"] as const;
type UpdatedData = { [key in typeof DataType]?: any };

But as @yudhiesh mentioned, making each field optional allows more than one field to be present (as well as no fields at all). If you're in a scenario where only one key should be allowed from a list of expected key values, then I'd recommend taking a look at this post instead: Enforce Typescript object has exactly one key from a set

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.