Как присвоить значение по умолчанию общему параметру?

У меня есть следующая функция:

function demo<T>(init: T) {
    return init;
}

Я хотел бы дать init значение по умолчанию {}, если оно опущено. Итак, я написал:

function demo2<T>(init: T = {}) {
    return init;
}

Но, конечно, это дает мне ошибку:

Type '{}' is not assignable to type 'T'.
  'T' could be instantiated with an arbitrary type which could be unrelated to '{}'.(2322)

Ссылка на детскую площадку.

Как я могу заставить T быть {}, если параметр опущен? Спасибо.

вы не можете гарантировать, что расширенный тип также будет частичным. interface Derived extends Partial<ListVariables>{ bbb: string; } . Попробуйте передать переменную этого типа.

Anatoly 09.12.2020 18:25

@ Анатолий Да, но есть ли способ автоматически изменить тип пустого объекта на T, когда параметр опущен?

ostrebler 09.12.2020 18:27

Как? Если вы используете useListVariables<Derived>, вы не можете использовать {} в качестве значения по умолчанию.

Anatoly 09.12.2020 18:29

Не могли бы вы отредактировать этот код, чтобы он был минимально воспроизводимым примером , подходящим для добавления в автономную IDE, такую ​​как The TypeScript Playground? Прежде чем публиковать ответы, мне хотелось бы иметь возможность проверить их на примере варианта использования, но я не знаю, что такое ListVariables, и я не уверен, какие результаты вы хотите увидеть для различных вариантов использования useListVariables() (например, что, если кто-то вручную указывает параметр типа, а не позволяет компилятору вывести его). Любой код, который показывает, что вы пробовали. Спасибо!

jcalz 09.12.2020 19:27

@jcalz Готово!

ostrebler 10.12.2020 02:42
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
0
5
165
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ошибка технически верна; вызывающим сторонам вашей функции demo2() разрешено указывать параметр типа T таким, каким они хотят его видеть. Это означает, что вызов, подобный следующему, не приведет к ошибке компилятора, но легко приведет к ошибке времени выполнения:

const z2 = demo2<{ a: number }>(); // uh oh, no error 
z2.a.toFixed(); // no error at compile time but "z2.a is undefined" at runtime

Тем не менее, если вы считаете, что вероятность того, что кто-то сделает это (ручное указание параметра универсального типа) низка, вы можете использовать утверждение типа для подавления ошибки, в то же время используя универсальный параметр по умолчанию, поэтому что компилятор выведет {} вместо T, если вы пропустите свойство init:

// assertion with default type parameter
function demo3<T = {}>(init: T = {} as T) {
    return init;
}

Это дает вам следующее желаемое поведение:

const x3 = demo3(); // {}
const y3 = demo3({ a: 123 }); // {a: number}

при этом допуская следующее нежелательное поведение:

const z3 = demo3<{ a: number }>(); // no compiler error
z3.a.toFixed(); // RUNTIME ERROR!

Если вы хотите запретить указание T вручную без передачи значения типа T, вы можете рассмотреть возможность использования чего-то вроде перегруженной функции с несколькими сигнатурами вызова:

// перегрузка

function demo4(): {};
function demo4<T>(init: T): T;
function demo4(init = {}) {
    return init;
}

Здесь, если вызывающая сторона пропускает параметр init, функция больше не рассматривается как универсальная; тип возврата просто {}. С другой стороны, если вызывающая сторона предоставляет параметр init, то функция обрабатывается так же, как ваша исходная функция demo(). Реализация функции работает для любой сигнатуры вызова.

Это также приводит к желательному поведению для «обычных» вызовов:

const x4 = demo4(); // {}
const y4 = demo4({ a: 123 }); // {a: number}

А также выдает предупреждение компилятору, если кто-то попытается назвать это неправильно:

const z4 = demo4<{ a: number }>(); // compiler error! an argument for init is required

Площадка ссылка на код

Другие вопросы по теме

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