英文:
Type where object cannot have property
问题
I'm wondering if it's possible in TypeScript to provide some sort of intersection type that requires a type to not have a specific property. For my example, I have a bunch of models from the database.
type User = {
id: number,
name: string,
email: string,
created_at: Date,
updated_at: Date,
password: string
}
What I want is a way to define some ResultWithoutSensitiveData<T>
type, which says "User CANNOT have created_at, updated_at, and password". Something that is basically Omit
or Pick
with keys instead of types. I've tried some form of conditional infer resulting in never
, but I end up with compiler complaints about how undefined can't be assigned to type never. I just can't get it quite right.
I want the compiler and IDE to tell devs if they haven't removed sensitive properties.
英文:
I'm wondering if it's possible in TypeScript to provide some sort of intersection type that requires a type to not have a specific property. For my example, I have a bunch of models from the database.
type User = {
id: number,
name: string,
email: string,
created_at: Date,
updated_at: Date,
password: string
}
What I want is a way to define some ResultWithoutSensitiveData<T>
type, which says "User CANNOT have created_at, updated_at, and password". Something that is basically Omit
or Pick
with keys instead of types. I've tried some form of conditional infer resulting in never
, but I end up with compiler complaints about how undefined can't be assigned to type never. I just can't get it quite right.
I want the compiler and IDE to tell devs if they haven't removed sensitive properties.
答案1
得分: 1
Combine Omit
and never
:
type SensitiveKeys = 'created_at' | 'updated_at' | 'password';
type ResultWithoutSensitiveData<T> = Omit<T, SensitiveKeys> & {
[key in SensitiveKeys]?: never; // the question mark is to make the keys optional to type T
};
你可以在 playground 上查看。
英文:
Combine Omit
and never
:
type SensitiveKeys = 'created_at' | 'updated_at' | 'password';
type ResultWithoutSensitiveData<T> = Omit<T, SensitiveKeys> & {
[key in SensitiveKeys]?: never; // the question mark is to make the keys optional to type T
};
You can have a look at the playground.
答案2
得分: 0
You need optional never
. Depending on your exactOptionalPropertyTypes
config they may look like password?: never
or password?: undefined
(as TS adds | undefined
to all optional properties if exactOptionalPropertyTypes
is off).
However, note that you can assign a value of type let x: {a: 1, password: 1}
to let y: {a: 1}
, which you can assign to let z: {a: 1, password?: never}
, so a runtime check may be better. Generally, having validators for all the inputs and outputs of your server is recommended.
type CleanUser = {
id: number,
name: string,
email: string,
created_at?: never,
updated_at?: never,
password?: never,
}
type User = {
id: number,
name: string,
email: string,
created_at: Date,
updated_at: Date,
password: string
}
type sensitiveKey = 'created_at' | 'updated_at' | 'password';
type Pure<T> = T extends infer R ? {[K in keyof R]: T[K]} : T;
type ResultWithoutSensitiveData<T> = Pure<Omit<T, sensitiveKey> & Partial<Record<Extract<keyof T, sensitiveKey>, never>>>;
type User1 = ResultWithoutSensitiveData<User>;
// ^?
// type User1 = {
// id: number;
// name: string;
// email: string;
// created_at?: undefined;
// updated_at?: undefined;
// password?: undefined;
// }
import { type } from "arktype";
const CleanUser = type(
{
id: "number",
name: "string",
email: "email"
},
{ keys: "strict" }
)
CleanUser.assert({
id: 123,
name: "asd",
email: "a@b.com",
password: "blah"
})
// ^! runtime error
// ParseError: password must be removed
英文:
You need optional never
.
Depending on your exactOptionalPropertyTypes
config they may look like password?: never
or password?: undefined
(as TS adds | undefined
to all optional properties if exactOptionalPropertyTypes
is off)
Hovewer, note that you can assign value of type let x: {a: 1, password: 1}
to let y: {a: 1}
, which you can assign to let z: {a: 1, password?: never}
, so a runtime check may be better
Generally, having validators for all the inputs and outputs of your server is recommented
type CleanUser = {
id: number,
name: string,
email: string,
created_at?: never,
updated_at?: never,
password?: never,
}
type User = {
id: number,
name: string,
email: string,
created_at: Date,
updated_at: Date,
password: string
}
type sensitiveKey = 'created_at' | 'updated_at' | 'password'
type Pure<T> = T extends infer R ? {[K in keyof R]: T[K]} : T;
type ResultWithoutSensitiveData<T> = Pure<Omit<T, sensitiveKey> & Partial<Record<Extract<keyof T, sensitiveKey>, never>>>
type User1 = ResultWithoutSensitiveData<User>
// ^?
// type User1 = {
// id: number;
// name: string;
// email: string;
// created_at?: undefined;
// updated_at?: undefined;
// password?: undefined;
// }
import { type } from "arktype"
const CleanUser = type(
{
id: "number",
name: "string",
email: "email"
},
{ keys: "strict" }
)
CleanUser.assert({
id: 123,
name: "asd",
email: "a@b.com",
password: "blah"
})
// ^! runtime error
// ParseError: password must be removed
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论