I am trying to generate two objects from one larger object to see if the property is listed within the given Generic type.
Meaning if I give something like:
{
name: "John",
enabled: false,
lastName: "Doe",
age: 33
}
and the type is:
type User = {
name: string;
lastName: string;
age: number
}
Result of function would be format of (Non In Type, InType)
[
{
enabled: false
},
{
name: "John",
lastName: "Doe",
age: 33
}
]
Here is what I have tried so far:
type GenericType<T> = Partial<T> & {
[record: string]: unknown
}
// Values are known properites of T
const sortProperties = <T>(values: string[], orginalObject: GenericType<T>){
const validPropertieis: Partial<T> = {};
const inValidProperties: Record<string, unknown> = {};
Object.keys(orginalObject).forEach((key) => {
if(values.includes(key){
// No index signature with parameter type 'string' was found on type Partial<T>
validPropertieis[key] = values[key];
}
else {
inValidProperties[key] = values[key];
}
return [inValidProperties, validProperties];
}
CodePudding user response:
EDIT:
Here's a solution:
// The valid properties we want
const arr = ['hi', 'test', 'abc'] as const;
const obj = {
hi: 'foo',
test: 420,
abc: 'bar',
// Oops, extra property
oops: 123,
};
const validateProperties = <A extends ReadonlyArray<string>, T extends Record<string, unknown>>(values: A, object: T) => {
return Object.keys(object).reduce((acc, key) => {
if (!values.includes(key)) acc[0] = { ...acc[0], [key]: object[key] };
else acc[1] = { ...acc[1], [key]: object[key] };
return acc;
}, [] as unknown as [Omit<T, A[number]>, Pick<T, A[number]>]);
};
const test = validateProperties(arr, obj);
Your IDE will autofill the properties when trying to access them. The only thing to note is that the string[]
must be either const
or a tuple of strings so that TypeScript can infer the literal types.
CodePudding user response:
Based on the description you gave I would suggest a solution like this:
type Expand<T> = T extends infer U ? { [K in keyof U]: U[K] } : never
type SortReturnType<K extends string, T> = [Expand<Omit<T, K>>, Expand<Pick<T, K & keyof T>>]
const sortProperties = <
K extends string,
T
>(v1: K[], v2: T): Expand<SortReturnType<K, T>> => {
const validProperties: Partial<T> = {};
const inValidProperties: Partial<T> = {};
Object.keys(v2).forEach((key) => {
if (v1.includes(key as any)) {
validProperties[key as keyof T] = v2[key as keyof T]
} else {
inValidProperties[key as keyof T] = v2[key as keyof T];
}
})
return [inValidProperties, validProperties] as SortReturnType<K, T>;
}
Let's see if it works.
const result = sortProperties(["name", "lastName", "age"], {
name: "abc",
lastName: "abc",
enabled: true,
age: 0
})
// const result: [{
// enabled: boolean;
// }, {
// name: string;
// lastName: string;
// age: number;
// }]
Look's fine to me. Let me know if this fits your requirements.
CodePudding user response:
Another try:
type User = {
name: string;
lastName: string;
age: number;
};
const testUser = {
name: "John",
enabled: false,
lastName: "Doe",
age: 33,
},
userTypeKeys = ["name", "lastName", "age"];
function sortProperties<T>(values: string[], object: T) {
const validProperties: Partial<T> = {},
invalidProperties: Record<string, unknown> = {};
Object.keys(object).forEach((key: string) => {
if (values.includes(key)) {
validProperties[key as keyof T] = object[key as keyof T];
} else {
invalidProperties[key] = object[key as keyof T];
}
});
return [invalidProperties, validProperties];
}
const properties = sortProperties(userTypeKeys, testUser);
// logs [ { enabled: false }, { name: 'John', lastName: 'Doe', age: 33 } ]
console.log(properties);