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

Property of a type is not assignable to Pick of this type #57138

Closed
Arctomachine opened this issue Jan 23, 2024 · 7 comments
Closed

Property of a type is not assignable to Pick of this type #57138

Arctomachine opened this issue Jan 23, 2024 · 7 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@Arctomachine
Copy link

🔎 Search Terms

"TS2322 pick"
"not assignable to pick"

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about Pick
  • I was unable to test this on prior versions because it already happens at oldest available version in playground - 3.3.3

⏯ Playground Link

https://www.typescriptlang.org/play?ts=5.4.0-dev.20240123#code/C4TwDgpgBAksEFsoF4oG8CwAoKurAEtgAbCAfgC4oBnYAJwIDsBzKAHykYFdjjsBfbNgDGAe0a0oRRFTiIU6bHnxFSVAOQALCL1HqBQrADMujYYXFQAhgApCJCFQAKBYQGsAPHIQAaKOvtSdQA+AEp0MQlRUgA6YlFmO1UIUMFjU3MCSwAjJIdnV09vPwDkkPYoUwATCCMmCCrwtEjqaIg4hLzSVOwTMwtGKGEuxygXdy94X39AiHKOatr6qoruXiaWto7E2Z6sbFtpBBjd7Fyjk+TQkRsL3aA

💻 Code

type Item = {
    title?: string | null
}

const item: Item = {
    title: 'hello'
}

function a(title: Pick<Item, 'title'>) {console.log(title)}
function b(title: Pick<Item, 'title'> | undefined) {console.log(title)}
function c(title: Pick<Item, 'title'> | undefined | null) {console.log(title)}

a(item.title)
b(item.title)
c(item.title)

🙁 Actual behavior

Type Item has property title which is string | null | undefined.
Trying to assign property title of type Item to consumer with type Pick<Item, 'title'> results in error ts2322 - cannot assign undefined to property which already supports undefined:

Argument of type 'string | null | undefined' is not assignable to parameter of type 'Pick<Item, "title">'.
  Type 'undefined' is not assignable to type 'Pick<Item, "title">'.

But what if we explicitly add undefined to consumer? Pick<Item, 'title'> | undefined results in same error ts2322 - but now it is about null, which consumer already supports:

Argument of type 'string | null | undefined' is not assignable to parameter of type 'Pick<Item, "title"> | undefined'.
  Type 'null' is not assignable to type 'Pick<Item, "title"> | undefined'.

What if we explicitly add null to consumer too? Pick<Item, 'title'> | undefined | null results in same error ts2322 - but now that we manually redefined two thirds of initial type, it fails to assign string to the only remaining option from picked type, which is string:

Argument of type 'string | null | undefined' is not assignable to parameter of type 'Pick<Item, "title"> | null | undefined'.
  Type 'string' has no properties in common with type 'Pick<Item, "title">'.

🙂 Expected behavior

All 3 options (pick, pick undefined, pick undefined null) should work without error because all possible types of consumer are derived (and/or overwritten by identical types) from the same type definition that argument in function call uses - thus both have exactly same type.

Additional information about the issue

I searched for other occurrences of ts2322 error, but non of them were in context of Pick, and workarounds for them were not applicable here.

@MartinJohns
Copy link
Contributor

MartinJohns commented Jan 23, 2024

The type of Pick<Item, 'title'> is { title?: string | null | undefined }. It is not string | null | undefined.

Pick<> is basically "give me an object with only these properties". However, you seem to want Item["title"].

@Arctomachine
Copy link
Author

Right. Probably I oversimplified my example. I will see if I can reproduce it with more complex types.

@Arctomachine
Copy link
Author

I made more complex example that shows problem I encountered in real code.
playground

Code:

type Item = {
    title: string
    categories?: (string | Category)[] | null
}

type Category = {
    id: string
    slug: string
}

const allItems:Item[] = []

type ItemNarrowed = Pick<Item, 'title'> & {
    categories?: Pick<Category, 'id' | 'slug'>[] // | null
}
function a(item: ItemNarrowed) {console.log(item)}

allItems
    .filter(item => typeof item.categories !== 'undefined' && item.categories !== null && !!item.categories) // only items where categories is not null and not undefined
    // function call gives error: Type 'null' is not assignable to type 'Pick<Category, "id" | "slug">[] | undefined'.
    
    .filter(item => Array.isArray(item.categories)) // only items where categories is array (same as previous filter)
    // gives same error


    .filter(item => typeof item.categories !== 'string') // only items whre item.categories is Category
    // if you uncomment null in ItemNarrowed.categories, it will give this error instead: Type 'string' is not assignable to type 'Pick<Category, "id" | "slug">'.
    
    .forEach(item => {
        a(item)
    })

So unless I did something wrong, .filter() does nothing for type narrowing.

@fatcerberus
Copy link

fatcerberus commented Jan 23, 2024

So unless I did something wrong, .filter() does nothing for type narrowing.

That's correct: type predicates are not automatically inferred. You need to write e.g. .filter((item): item is ItemNarrowed => ...) to get it to narrow. If this is the only underlying issue for you then this is ultimately a duplicate of #16069.

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Jan 23, 2024
@Arctomachine
Copy link
Author

Yes, it appears to be the only actual problem.
This workaround feels strange, but if it works - it works.
Since it is duplicate, is there estimated timeline for it? Original topic started 7 years ago already, but progress is still unknown to public.

@RyanCavanaugh
Copy link
Member

All our progress, commits, and meeting notes are public. For approximately all things, if you don't see it here, it's not being worked on due to the other work you see having higher priority.

@typescript-bot
Copy link
Collaborator

This issue has been marked as "Question" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Jan 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

5 participants