Skip to content

Commit

Permalink
SetFieldType: Add option to preserve property modifiers (#1017)
Browse files Browse the repository at this point in the history
  • Loading branch information
som-sm authored Dec 25, 2024
1 parent 8df6909 commit 59517cb
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 12 deletions.
44 changes: 32 additions & 12 deletions source/set-field-type.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import type {Except} from './except';
import type {Simplify} from './simplify';

type SetFieldTypeOptions = {
/**
Preserve optional and readonly modifiers for properties being updated.
NOTE: Property modifiers will always be preserved for properties that are not being updated.
@default true
*/
preservePropertyModifiers?: boolean;
};

/**
Create a type that changes the type of the given keys.
Expand All @@ -15,23 +25,33 @@ Use-cases:
import type {SetFieldType} from 'type-fest';
type MyModel = {
id: number;
createdAt: Date;
updatedAt: Date;
readonly id: number;
readonly createdAt: Date;
updatedAt?: Date;
};
type MyModelApi = SetFieldType<MyModel, 'createdAt' | 'updatedAt', string>;
// {
// id: number;
// createdAt: string;
// updatedAt: string;
// readonly id: number;
// readonly createdAt: string;
// updatedAt?: string;
// }
// `preservePropertyModifiers` option can be set to `false` if you want to remove property modifiers for properties being updated
type MyModelApi = SetFieldType<MyModel, 'createdAt' | 'updatedAt', string, {preservePropertyModifiers: false}>;
// {
// readonly id: number;
// createdAt: string; // no longer readonly
// updatedAt: string; // no longer optional
// }
```
@category Object
*/
export type SetFieldType<BaseType, Keys extends keyof BaseType, NewType> =
Simplify<
Except<BaseType, Keys> &
Record<Keys, NewType>
>;
export type SetFieldType<BaseType, Keys extends keyof BaseType, NewType, Options extends SetFieldTypeOptions = {preservePropertyModifiers: true}> =
Simplify<{
[P in keyof BaseType]: P extends Keys ? NewType : BaseType[P];
} & (
// `Record` is used to remove property modifiers
Options['preservePropertyModifiers'] extends false ? Record<Keys, NewType> : unknown
)>;
26 changes: 26 additions & 0 deletions test-d/set-field-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,29 @@ expectType<{a: string; b: number; c: number}>(variation3);

declare const variation4: SetFieldType<{a: string; b: string; c: string}, 'b', number>;
expectNotAssignable<{a: string; b: string; c: string}>(variation4);

// Works with union types
declare const variation5: SetFieldType<{a: string; b: string} | {a: number; c: number}, 'a', boolean>;
expectType<{a: boolean; b: string} | {a: boolean; c: number}>(variation5);

declare const variation6: SetFieldType<{a: string; b: string} | {a: number; c: number}, 'a', boolean, {preservePropertyModifiers: false}>;
expectType<{a: boolean; b: string} | {a: boolean; c: number}>(variation6);

// Property modifiers are always preserved for properties that are not being updated
declare const variation7: SetFieldType<{a?: string; readonly b: string; c: string}, 'c', number>;
expectType<{a?: string; readonly b: string; c: number}>(variation7);

declare const variation8: SetFieldType<{a?: string; readonly b: string; c: string}, 'c', number, {preservePropertyModifiers: false}>;
expectType<{a?: string; readonly b: string; c: number}>(variation8);

// Preserves property modifiers
declare const variation9: SetFieldType<{a?: string; readonly b: string; readonly c?: string}, 'a' | 'c', number>;
expectType<{a?: number; readonly b: string; readonly c?: number}>(variation9);

// Doesn't preserve property modifiers when `preservePropertyModifiers` is `false`
declare const variation10: SetFieldType<{a?: string; readonly b: string; readonly c?: string}, 'a' | 'c', number, {preservePropertyModifiers: false}>;
expectType<{a: number; readonly b: string; c: number}>(variation10);

// Falls back to default of `true`, if `preservePropertyModifiers` is set to `boolean`
declare const variation11: SetFieldType<{a?: string; readonly b: string; readonly c?: string}, 'a' | 'c', number, {preservePropertyModifiers: boolean}>;
expectType<{a?: number; readonly b: string; readonly c?: number}>(variation11);

0 comments on commit 59517cb

Please sign in to comment.