feat(ui): replace type-fest with utility-types

- The new package has more useful types
- Only used `JsonObject` from `type-fest`; added an implementation of that type
This commit is contained in:
psychedelicious 2024-02-22 17:19:08 +11:00
parent cc41e8912c
commit 0d9fbe5e04
7 changed files with 73 additions and 34 deletions

View File

@ -99,7 +99,6 @@
"roarr": "^7.21.0", "roarr": "^7.21.0",
"serialize-error": "^11.0.3", "serialize-error": "^11.0.3",
"socket.io-client": "^4.7.4", "socket.io-client": "^4.7.4",
"type-fest": "^4.10.2",
"use-debounce": "^10.0.0", "use-debounce": "^10.0.0",
"use-image": "^1.1.1", "use-image": "^1.1.1",
"uuid": "^9.0.1", "uuid": "^9.0.1",
@ -146,6 +145,7 @@
"ts-toolbelt": "^9.6.0", "ts-toolbelt": "^9.6.0",
"tsafe": "^1.6.6", "tsafe": "^1.6.6",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"utility-types": "^3.11.0",
"vite": "^5.1.3", "vite": "^5.1.3",
"vite-plugin-css-injected-by-js": "^3.4.0", "vite-plugin-css-injected-by-js": "^3.4.0",
"vite-plugin-dts": "^3.7.2", "vite-plugin-dts": "^3.7.2",

View File

@ -152,9 +152,6 @@ dependencies:
socket.io-client: socket.io-client:
specifier: ^4.7.4 specifier: ^4.7.4
version: 4.7.4 version: 4.7.4
type-fest:
specifier: ^4.10.2
version: 4.10.2
use-debounce: use-debounce:
specifier: ^10.0.0 specifier: ^10.0.0
version: 10.0.0(react@18.2.0) version: 10.0.0(react@18.2.0)
@ -271,6 +268,9 @@ devDependencies:
typescript: typescript:
specifier: ^5.3.3 specifier: ^5.3.3
version: 5.3.3 version: 5.3.3
utility-types:
specifier: ^3.11.0
version: 3.11.0
vite: vite:
specifier: ^5.1.3 specifier: ^5.1.3
version: 5.1.3(@types/node@20.11.19) version: 5.1.3(@types/node@20.11.19)
@ -13827,11 +13827,6 @@ packages:
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
engines: {node: '>=12.20'} engines: {node: '>=12.20'}
/type-fest@4.10.2:
resolution: {integrity: sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==}
engines: {node: '>=16'}
dev: false
/type-is@1.6.18: /type-is@1.6.18:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@ -14152,6 +14147,11 @@ packages:
which-typed-array: 1.1.14 which-typed-array: 1.1.14
dev: true dev: true
/utility-types@3.11.0:
resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==}
engines: {node: '>= 4'}
dev: true
/utils-merge@1.0.1: /utils-merge@1.0.1:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'} engines: {node: '>= 0.4.0'}

View File

@ -3,6 +3,7 @@ import { autoBatchEnhancer, combineReducers, configureStore } from '@reduxjs/too
import { logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import { idbKeyValDriver } from 'app/store/enhancers/reduxRemember/driver'; import { idbKeyValDriver } from 'app/store/enhancers/reduxRemember/driver';
import { errorHandler } from 'app/store/enhancers/reduxRemember/errors'; import { errorHandler } from 'app/store/enhancers/reduxRemember/errors';
import type { JSONObject } from 'common/types';
import { canvasPersistConfig, canvasSlice } from 'features/canvas/store/canvasSlice'; import { canvasPersistConfig, canvasSlice } from 'features/canvas/store/canvasSlice';
import { changeBoardModalSlice } from 'features/changeBoardModal/store/slice'; import { changeBoardModalSlice } from 'features/changeBoardModal/store/slice';
import { import {
@ -32,7 +33,6 @@ import { rememberEnhancer, rememberReducer } from 'redux-remember';
import { serializeError } from 'serialize-error'; import { serializeError } from 'serialize-error';
import { api } from 'services/api'; import { api } from 'services/api';
import { authToastMiddleware } from 'services/api/authToastMiddleware'; import { authToastMiddleware } from 'services/api/authToastMiddleware';
import type { JsonObject } from 'type-fest';
import { STORAGE_PREFIX } from './constants'; import { STORAGE_PREFIX } from './constants';
import { actionSanitizer } from './middleware/devtools/actionSanitizer'; import { actionSanitizer } from './middleware/devtools/actionSanitizer';
@ -125,7 +125,7 @@ const unserialize: UnserializeFunction = (data, key) => {
{ {
persistedData: parsed, persistedData: parsed,
rehydratedData: transformed, rehydratedData: transformed,
diff: diff(parsed, transformed) as JsonObject, // this is always serializable diff: diff(parsed, transformed) as JSONObject, // this is always serializable
}, },
`Rehydrated slice "${key}"` `Rehydrated slice "${key}"`
); );

View File

@ -0,0 +1,7 @@
export type JSONValue = string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue };
export interface JSONObject {
[k: string]: JSONValue;
}
export interface JSONArray extends Array<JSONValue> {}

View File

@ -1,5 +1,5 @@
import type { JSONObject } from 'common/types';
import type { CoreMetadataInvocation, NonNullableGraph } from 'services/api/types'; import type { CoreMetadataInvocation, NonNullableGraph } from 'services/api/types';
import type { JsonObject } from 'type-fest';
import { METADATA } from './constants'; import { METADATA } from './constants';
@ -30,7 +30,7 @@ export const addCoreMetadataNode = (
export const upsertMetadata = ( export const upsertMetadata = (
graph: NonNullableGraph, graph: NonNullableGraph,
metadata: Partial<CoreMetadataInvocation> | JsonObject metadata: Partial<CoreMetadataInvocation> | JSONObject
): void => { ): void => {
const metadataNode = graph.nodes[METADATA] as CoreMetadataInvocation | undefined; const metadataNode = graph.nodes[METADATA] as CoreMetadataInvocation | undefined;

View File

@ -1,3 +1,4 @@
import type { JSONObject } from 'common/types';
import { parseify } from 'common/util/serialize'; import { parseify } from 'common/util/serialize';
import type { InvocationTemplate } from 'features/nodes/types/invocation'; import type { InvocationTemplate } from 'features/nodes/types/invocation';
import type { WorkflowV3 } from 'features/nodes/types/workflow'; import type { WorkflowV3 } from 'features/nodes/types/workflow';
@ -5,14 +6,13 @@ import { isWorkflowInvocationNode } from 'features/nodes/types/workflow';
import { getNeedsUpdate } from 'features/nodes/util/node/nodeUpdate'; import { getNeedsUpdate } from 'features/nodes/util/node/nodeUpdate';
import { t } from 'i18next'; import { t } from 'i18next';
import { keyBy } from 'lodash-es'; import { keyBy } from 'lodash-es';
import type { JsonObject } from 'type-fest';
import { parseAndMigrateWorkflow } from './migrations'; import { parseAndMigrateWorkflow } from './migrations';
type WorkflowWarning = { type WorkflowWarning = {
message: string; message: string;
issues?: string[]; issues?: string[];
data: JsonObject; data: JSONObject;
}; };
type ValidateWorkflowResult = { type ValidateWorkflowResult = {

View File

@ -2,7 +2,7 @@ import type { UseToastOptions } from '@invoke-ai/ui-library';
import type { EntityState } from '@reduxjs/toolkit'; import type { EntityState } from '@reduxjs/toolkit';
import type { components, paths } from 'services/api/schema'; import type { components, paths } from 'services/api/schema';
import type { O } from 'ts-toolbelt'; import type { O } from 'ts-toolbelt';
import type { SetRequired } from 'type-fest'; import type { Overwrite } from 'utility-types';
export type S = components['schemas']; export type S = components['schemas'];
@ -61,28 +61,60 @@ export type IPAdapterField = S['IPAdapterField'];
// Model Configs // Model Configs
// TODO(MM2): Can we make key required in the pydantic model? // TODO(MM2): Can we make key required in the pydantic model?
type KeyRequired<T extends { key?: string }> = SetRequired<T, 'key'>; export type LoRAModelConfig = S['LoRAConfig'];
export type LoRAConfig = KeyRequired<S['LoRAConfig']>;
// TODO(MM2): Can we rename this from Vae -> VAE // TODO(MM2): Can we rename this from Vae -> VAE
export type VAEConfig = KeyRequired<S['VaeCheckpointConfig']> | KeyRequired<S['VaeDiffusersConfig']>; export type VAEModelConfig = S['VaeCheckpointConfig'] | S['VaeDiffusersConfig'];
export type ControlNetConfig = export type ControlNetModelConfig = S['ControlNetDiffusersConfig'] | S['ControlNetCheckpointConfig'];
| KeyRequired<S['ControlNetDiffusersConfig']> export type IPAdapterModelConfig = S['IPAdapterConfig'];
| KeyRequired<S['ControlNetCheckpointConfig']>;
export type IPAdapterConfig = KeyRequired<S['IPAdapterConfig']>;
// TODO(MM2): Can we rename this to T2IAdapterConfig // TODO(MM2): Can we rename this to T2IAdapterConfig
export type T2IAdapterConfig = KeyRequired<S['T2IConfig']>; export type T2IAdapterModelConfig = S['T2IConfig'];
export type TextualInversionConfig = KeyRequired<S['TextualInversionConfig']>; export type TextualInversionModelConfig = S['TextualInversionConfig'];
export type DiffusersModelConfig = KeyRequired<S['MainDiffusersConfig']>; export type DiffusersModelConfig = S['MainDiffusersConfig'];
export type CheckpointModelConfig = KeyRequired<S['MainCheckpointConfig']>; export type CheckpointModelConfig = S['MainCheckpointConfig'];
export type MainModelConfig = DiffusersModelConfig | CheckpointModelConfig; export type MainModelConfig = DiffusersModelConfig | CheckpointModelConfig;
export type RefinerMainModelConfig = Overwrite<MainModelConfig, { base: 'sdxl-refiner' }>;
export type NonRefinerMainModelConfig = Overwrite<MainModelConfig, { base: 'any' | 'sd-1' | 'sd-2' | 'sdxl' }>;
export type AnyModelConfig = export type AnyModelConfig =
| LoRAConfig | LoRAModelConfig
| VAEConfig | VAEModelConfig
| ControlNetConfig | ControlNetModelConfig
| IPAdapterConfig | IPAdapterModelConfig
| T2IAdapterConfig | T2IAdapterModelConfig
| TextualInversionConfig | TextualInversionModelConfig
| MainModelConfig; | RefinerMainModelConfig
| NonRefinerMainModelConfig;
export const isLoRAModelConfig = (config: AnyModelConfig): config is LoRAModelConfig => {
return config.type === 'lora';
};
export const isVAEModelConfig = (config: AnyModelConfig): config is VAEModelConfig => {
return config.type === 'vae';
};
export const isControlNetModelConfig = (config: AnyModelConfig): config is ControlNetModelConfig => {
return config.type === 'controlnet';
};
export const isIPAdapterModelConfig = (config: AnyModelConfig): config is IPAdapterModelConfig => {
return config.type === 'ip_adapter';
};
export const isT2IAdapterModelConfig = (config: AnyModelConfig): config is T2IAdapterModelConfig => {
return config.type === 't2i_adapter';
};
export const isTextualInversionModelConfig = (config: AnyModelConfig): config is TextualInversionModelConfig => {
return config.type === 'embedding';
};
export const isNonRefinerMainModelConfig = (config: AnyModelConfig): config is NonRefinerMainModelConfig => {
return config.type === 'main' && config.base !== 'sdxl-refiner';
};
export const isRefinerMainModelModelConfig = (config: AnyModelConfig): config is RefinerMainModelConfig => {
return config.type === 'main' && config.base === 'sdxl-refiner';
};
export type MergeModelConfig = S['Body_merge']; export type MergeModelConfig = S['Body_merge'];
export type ImportModelConfig = S['Body_import_model']; export type ImportModelConfig = S['Body_import_model'];