Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot safely, generically add a property to a record #38796

Closed
SLaks opened this issue May 27, 2020 · 5 comments
Closed

Cannot safely, generically add a property to a record #38796

SLaks opened this issue May 27, 2020 · 5 comments
Labels
Needs More Info The issue still hasn't been fully clarified

Comments

@SLaks
Copy link

SLaks commented May 27, 2020

TypeScript Version: v4.0.0-dev.20200525, 3.9.2

Search Terms: object intersection record

Code

function add<TShape, TName extends string, TValue>(
    obj: TShape, name: TName, value: TValue): TShape & Record<TName, TValue> {
  return {...obj, [name]: value};
}

Expected behavior:

No compiler errors

Actual behavior:

Type 'TShape & { [x: string]: TValue; }' is not assignable to type 'TShape & Record<TName, TValue>'. Type 'TShape & { [x: string]: TValue; }' is not assignable to type 'Record<TName, TValue>'.

Playground Link

Additional attempts:

I couldn't find any way to make this work without a cast; no matter what I tried, the property [name]: value is inferred as [x: string]: TValue, ignoring TName. Other attempt:

  const addition: {[name in TName]: TValue} = {[name]: value};
  return {...obj, ...addition};
Type '{ [x: string]: TValue; }' is not assignable to type '{ [name in TName]: TValue; }'.

Playground Link

Related Issues: Possibly #18538

@SLaks
Copy link
Author

SLaks commented May 27, 2020

On further thought, this wouldn't actually be safe, because TName could also be a union:

const bad = add<{x: 1}, 'a'|'b', 'Oops'>({x: 1}, 'a', 'Oops');
bad.b;

Playground Link

I guess this is a feature request then, to have some way of accepting a single property name as a parameter so this can be safe. I don't have a specific design offhand.

@SLaks
Copy link
Author

SLaks commented May 27, 2020

Motivation

I want to create a hierachical builder that accepts property names as strings and builds an object with those properties.

For (a simplified) example:

Playground Link

@RyanCavanaugh RyanCavanaugh added the Needs More Info The issue still hasn't been fully clarified label Jun 1, 2020
@RyanCavanaugh
Copy link
Member

I can't tell what you're trying to do here - please boil this down to something more actionable if you'd like us to follow up more. Thanks!

@SLaks
Copy link
Author

SLaks commented Jun 7, 2020

General feature request

Have a type-safe way to accept a string parameter and use it as a property name. In other words, a way to write the following code without the cast:

function add<TObject, TName extends string, TValue>(
    obj: TObject, name: TName, value: TValue) {
  return {...obj, [name]: value} as TObject & {[name in TName]: TValue};
}

This may require some way of accepting a single property name as a parameter (as opposed to 'a' | 'b') so this can be safe.

@RyanCavanaugh
Copy link
Member

Got it - this would be a duplicate (or at least dependent on) of #27808 then

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs More Info The issue still hasn't been fully clarified
Projects
None yet
Development

No branches or pull requests

2 participants