Imagine we have some interface:
export type User = {
id: number
name: string
}
Working as expected:
And we have a function register1 that accepts Partial of this type:
function register1(userProperties: Partial<User>) {
}
register1({
id: 1,
name: "Anders",
})
And I want to prevent incident properties passing to that function:
register1({
id: 1,
name2: "Anders", // gives me error, great!
})
Not working as expected:
Now imagine I have a register2 function that does the same, and a bit more:
function register2<T extends Partial<User>>(properties: T) {
// I want to pass T down the road to another function,
// and that function returns type-safe result based on actually passed properties
// let's imagine that function changes given property values to boolean
return someAnotherFunctionCall<T>(properties)
}
register2({
id: 1,
}) // returns { id: boolean }
register2({
id: 1,
name2: "Anders"
}) // returns { id: boolean } as expected
Everything works as I need besides one thing - I would like compiler to throw error on name2 property - "missing property name2 on PartialT extends Partial<User> means T is extended version of PartialT extends const Partial<User> syntax should be suggested?
It can be a duplicate, I didn't know how to describe problem properly. If it's a new feature please help me to update the issue title. Thanks.
export type User = {
id: number
name: string
}
function someAnotherFunctionCall<T extends Partial<User>> (properties : T) {
}
function register2<T extends Partial<User>>(
properties: (
T &
(
keyof T extends keyof User ?
unknown :
["Extra property not allowed; ", Exclude<keyof T, keyof User>]
)
)
) {
// I want to pass T down the road to another function,
// and that function returns type-safe result based on actually passed properties
// let's imagine that function changes given property values to boolean
return someAnotherFunctionCall<T>(properties)
}
register2({
id: 1,
}) // returns { id: boolean }
register2({
id: 1,
name2: "Anders"
}) // returns { id: boolean } as expected
Not sure if there's another way at the moment.
Maybe someone else will come along and have a better workaround.
It's very rare that these signatures can't be rewritten in a way that works. What's the definition of someAnotherFunctionCall ?
Let me write a very simple implementation of what I have:
export type User = {
id: number
name: string
}
export type Selection<T, K extends keyof T> = {
[P in K]?: boolean
}
export type ModelSelection<T, S extends Selection<T, keyof T>> = {
[P in keyof T]: S[P] extends true ? T[P] : never
}
function select<T, S extends Selection<T, keyof T>>(model: T, selection: S): ModelSelection<T, S> {
return undefined as any
}
const user: User = {
id: 1,
name: "Anders",
}
const selection = select(user, {
id: true,
name2: false // I want to have error here
})
// type of selection is { id: number, name: never } here
// is expected (but really would like not to have "name" in type signature at all, but that's another case)
It seems like what you really want is exact types, in which case this would be a duplicate of #12936.
@fatcerberus yes, it looks so, thanks for reference
@fatcerberus seems like your observation is true once again. The people that want exact types and similar things tend to be people working with data stores
This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.
Most helpful comment
It seems like what you really want is exact types, in which case this would be a duplicate of #12936.