@CyberTopTuK
...

Типизация функции, возвращающей разные объекты?

Мастера тайпскрипта, подскажите, пожалуйста, как типизировать такую функцию.

export function getElementSettings(type: keyof typeof elementTypes) {
  switch (type) {
    case 'welcome':
      return {
        placeholder: 'Type welcome message...',
        question: '',
        isDescription: false,
        description: '',
        startButtonText: 'Start',
      };
    case 'checkbox':
      return {
        placeholder: 'Type question or statement...',
        question: '',
        isDescription: false,
        description: '',
        options: [],
        multiple: false,
      };
    case 'dropdown':
      return {
        placeholder: 'Type question here...',
        question: '',
        isDescription: false,
        description: '',
        options: [],
      };
    case 'rating':
      return {
        placeholder: 'Type question...',
        question: '',
        isDescription: false,
        description: '',
        steps: 10,
        defaultRate: 0,
        shape: 'stars',
      };
    case 'text':
      return {
        placeholder: 'Type question...',
        question: '',
        isDescription: false,
        description: '',
        maxLength: 99999,
      };
    case 'slider':
      return {
        placeholder: 'Type question...',
        question: '',
        isDescription: false,
        description: '',
        steps: 10,
      };
    case 'thanks':
      return {
        placeholder: 'Type message...',
        question: '',
        isDescription: false,
        description: '',
      };
    default:
      throw new Error("element type doesn't match!");
  }
}


поля options - массив строк.

Или же может быть есть более лучший способ организовать создание таких объектов?
  • Вопрос задан
  • 142 просмотра
Решения вопроса 2
Aetae
@Aetae Куратор тега TypeScript
Тлен
Проще всего сделать так, ts сам подберёт типы:
const elementDefaults = {
  'welcome': {
    placeholder: 'Type welcome message...',
    question: '',
    isDescription: false,
    description: '',
    startButtonText: 'Start',
  },
  'checkbox': {
    placeholder: 'Type question or statement...',
    question: '',
    isDescription: false,
    description: '',
    options: [] as string[],
    multiple: false,
  }, 
  'dropdown': {
    placeholder: 'Type question here...',
    question: '',
    isDescription: false,
    description: '',
    options: [] as string[],
  },
  'rating': {
    placeholder: 'Type question...',
    question: '',
    isDescription: false,
    description: '',
    steps: 10,
    defaultRate: 0,
    shape: 'stars',
  },
  'text': {
    placeholder: 'Type question...',
    question: '',
    isDescription: false,
    description: '',
    maxLength: 99999,
  }, 
  'slider': {
    placeholder: 'Type question...',
    question: '',
    isDescription: false,
    description: '',
    steps: 10,
  }, 
  'thanks': {
    placeholder: 'Type message...',
    question: '',
    isDescription: false,
    description: '',
  }
}


export function getElementSettings<E extends keyof typeof elementTypes>(type: E) {
  if(!(type in elementDefaults)) throw new Error("element type doesn't match!");
  return elementDefaults[type];
}

Но если хочется по правилам, то как-то так:
type ElementSetting = {
  placeholder: string;
  question: string;
  isDescription: boolean;
  description: string;
}

type ElementSettings = {
  welcome: ElementSetting & {
    startButtonText: string;
  },
  checkbox: ElementSetting & {
    options: string[];
    multiple: boolean;
  },
  dropdown: ElementSetting & {
    options: string[];
  },
  rating: ElementSetting & {
    steps: number;
    defaultRate: number;
    shape: string;
  },
  text: ElementSetting & {
    maxLength: number;
  },
  slider: ElementSetting & {
    steps: number;
  },
  thanks: ElementSetting
}

const elementDefaults: ElementSettings = {
  'welcome': {
    placeholder: 'Type welcome message...',
    question: '',
    isDescription: false,
    description: '',
    startButtonText: 'Start',
  },
  'checkbox': {
    placeholder: 'Type question or statement...',
    question: '',
    isDescription: false,
    description: '',
    options: [],
    multiple: false,
  },
  'dropdown': {
    placeholder: 'Type question here...',
    question: '',
    isDescription: false,
    description: '',
    options: [],
  },
  'rating': {
    placeholder: 'Type question...',
    question: '',
    isDescription: false,
    description: '',
    steps: 10,
    defaultRate: 0,
    shape: 'stars',
  },
  'text': {
    placeholder: 'Type question...',
    question: '',
    isDescription: false,
    description: '',
    maxLength: 99999,
  },
  'slider': {
    placeholder: 'Type question...',
    question: '',
    isDescription: false,
    description: '',
    steps: 10,
  },
  'thanks': {
    placeholder: 'Type message...',
    question: '',
    isDescription: false,
    description: '',
  }
}


export function getElementSettings<E extends keyof ElementSettings>(type: E): ElementSettings[E] {
  if(!(type in elementDefaults)) throw new Error("element type doesn't match!");
  return elementDefaults[type];
}
Ответ написан
bingo347
@bingo347 Куратор тега TypeScript
Crazy on performance...
const elementSettings = {
  welcome: {
    placeholder: 'Type welcome message...',
    question: '',
    isDescription: false,
    description: '',
    startButtonText: 'Start',
  },
  checkbox: {
    placeholder: 'Type question or statement...',
    question: '',
    isDescription: false,
    description: '',
    options: [] as string[],
    multiple: false,
  }, 
  dropdown: {
    placeholder: 'Type question here...',
    question: '',
    isDescription: false,
    description: '',
    options: [] as string[],
  },
  rating: {
    placeholder: 'Type question...',
    question: '',
    isDescription: false,
    description: '',
    steps: 10,
    defaultRate: 0,
    shape: 'stars',
  },
  text: {
    placeholder: 'Type question...',
    question: '',
    isDescription: false,
    description: '',
    maxLength: 99999,
  }, 
  slider: {
    placeholder: 'Type question...',
    question: '',
    isDescription: false,
    description: '',
    steps: 10,
  }, 
  thanks: {
    placeholder: 'Type message...',
    question: '',
    isDescription: false,
    description: '',
  }
} as const;

type Editable<T> = { -readonly [P in keyof T]: T[P]; };
type ElementSettings = typeof elementSettings;

export function getElementSettings<T extends keyof ElementSettings>(type: T): Editable<ElementSettings[T]> {
  if(type in elementSettings) {
    const settings = {...elementSettings[type]};
    if('options' in settings) {
      (settings as {options: string[]}).options = (settings as {options: string[]}).options.slice();
    }
    return settings;
  }
  throw new Error("element type doesn't match!");
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы