Skip to content
Youngho Chaa cha cha
TwitterHomepage

Abstract out the common bit from TypeScript types

typescript, javascript2 min read

I often encounter situations in my TypeScript projects where I define similar looking types that share most of their structure but have slight differences. The duplication has been a dilemma for me, as I question whether I am tightly coupling types simply because they appear similar. While the issue remains unresolved, I have discovered a better approach to abstracting the common aspects. It’s using Omit<T> utility type

// before
export type Note = Identifiers<NoteType> & {
noteFor?: Identifiers<RecordType.ServiceUser>;
createdAt?: Iso8601String;
createdBy?: Identifiers<RecordType.Worker> | Worker;
action?: RecordWithType<NoteAction> & {
description?: string;
reviewedAt?: string;
reviewedBy?: Identifiers<RecordType.Worker> | Worker;
/** This is only optional or undefined for compatibility with reduce_triage_volume turned off. This should be required once that
* feature flag is removed.
*/
reviewOutcome?: string;
reasonForReview?: string;
};
description?: string;
incident?: string;
agreedAction?: string;
safeguardings?: Identifiers<RecordType.Safeguarding>[];
};
export type UpdateNotePayload = WithType<NoteType> & {
action?: RecordWithType<NoteAction> & {
description?: string;
reviewedAt?: string;
reviewedBy?: Identifiers<RecordType.Worker> | Worker;
/** This is only optional or undefined for compatibility with reduce_triage_volume turned off. This should be required once that
* feature flag is removed.
*/
reviewOutcome?: string;
reasonForReview?: string;
};
description?: string;
incident?: string;
agreedAction?: string;
safeguardings?: Identifiers<RecordType.Safeguarding>[];
}
export type CreateNotePayload = WithType<NoteType> & {
noteFor?: Identifiers<RecordType.ServiceUser>;
createdBy?: Identifiers<RecordType.Worker> | Worker;
action?: RecordWithType<NoteAction> & {
description?: string;
reviewedAt?: string;
reviewedBy?: Identifiers<RecordType.Worker> | Worker;
/** This is only optional or undefined for compatibility with reduce_triage_volume turned off. This should be required once that
* feature flag is removed.
*/
reviewOutcome?: string;
reasonForReview?: string;
};
description?: string;
incident?: string;
agreedAction?: string;
safeguardings?: Identifiers<RecordType.Safeguarding>[];
}
// after
export type Note = Identifiers<NoteType> & {
noteFor?: Identifiers<RecordType.ServiceUser>;
createdAt?: Iso8601String;
createdBy?: Identifiers<RecordType.Worker> | Worker;
action?: RecordWithType<NoteAction> & {
description?: string;
reviewedAt?: string;
reviewedBy?: Identifiers<RecordType.Worker> | Worker;
/** This is only optional or undefined for compatibility with reduce_triage_volume turned off. This should be required once that
* feature flag is removed.
*/
reviewOutcome?: string;
reasonForReview?: string;
};
description?: string;
incident?: string;
agreedAction?: string;
safeguardings?: Identifiers<RecordType.Safeguarding>[];
};
export type UpdateNotePayload = Omit<Note, 'noteFor' | 'createdAt' | 'createdBy' | '@id'>;
export type CreateNotePayload = Omit<Note, 'createdAt' | '@id'>;

By utilising the Omit<T> type, I’m able to exclude specific properties from the origin Note type, resulting in more concise and reusable UpdateNotePayload and CreateNotePayload types.

© 2024 by Youngho Chaa cha cha. All rights reserved.
Theme by LekoArts