Language-tools: Поддерживает типы объединения в свойствах и реактивном выражении.

Созданный на 21 июн. 2020  ·  28Комментарии  ·  Источник: sveltejs/language-tools

Ваш запрос функции связан с проблемой?
В следующем коде будет ошибка машинописного текста из-за анализа потока управления машинописным текстом.
Но это очень полезно, когда речь идет о компоненте select-wrapper.

<script lang="typescript">
  export let value: string | number = '';

  if (typeof value === 'number') {
    console.log(value.toFixed())
  }

</script>

<select bind:value={value}></select>

Опишите желаемое решение
В svelte2tsx props и реактивный оператор $: { } необходимо вывести из контекста потока управления, возможно, обернув его обратным вызовом следующим образом:

declare function __sveltets_invalidate<T>(getValue: () => T): T

/*export*/ let value: string | number = __sveltets_invalidate(() => '')

let b: 'A' | 'B' = 'A';

() => {
$: {
    console.log(b)
}
}

Дополнительный контекст
Добавьте любой другой контекст или скриншоты о запросе функции здесь.
圖片

enhancement

Все 28 Комментарий

Хорошая идея с недействительной оберткой вокруг реквизита. Может быть, тогда нам даже не нужно добавлять еще одну оболочку к реактивным операторам? Или есть ли случаи, когда это приведет к ошибкам потока управления?

измените export let на let и оберните оператор в $: {} будет иметь ту же ошибку

<script lang="typescript">
  let value: string | number = '';

  $: {
    if (typeof value === 'number') {
      console.log(value.toFixed())
    }
  }
</script>

если значение было переназначено обработчиком событий. Тип этого может измениться

А, не подумал об этом. Спасибо!

Обратный вызов функции для реквизита не будет работать, лол. Нужно найти другой путь.

Кстати, эту обертку можно использовать в переменной $:, если мы изменим первую метку $: на let, как мы обсуждали ранее в ветке общей стратегии. Потому что его тип зависит от другого let . Так бы работало.

Еще одна проблема: реквизиты этого типа объединения также будут иметь тип строки в экспортируемом определении реквизита по той же причине.

export let someProps : string | number = ''

К

declare function __sveltets__invalidateWithDefault<T>(getValue: () => T | undefined): T;

let someProps: string | number = ''
someProps = __sveltets__invalidateWithDefault(() => someProps);

Это работает, но как-то хакерски

export let test: string | number = '' as any;

работает

Решение @PatrickG лучше. но оба подхода сделают реквизит неопределенным типом.

export let test: string | number | undefined = '' as any;
test // test is shouldn't be undefined here

Можете ли вы каким-то образом получить типы из машинописного AST и использовать их для его создания? Или используйте какой-нибудь обход AST/регулярное выражение, чтобы получить определение типа (все после : и до = ), а затем поместите его за ним: export let test: string | number = '' as string | number .

Решение @PatrickG лучше. но оба подхода сделают реквизит неопределенным типом.

export let test: string | number | undefined = '' as any;
test // test is shouldn't be undefined here

для меня тест string | number . Не undefined .
image

пример детской площадки
Это будет undefined , если strictNullChecks включено (также включите strict: true )

пример детской площадки
Это будет undefined , если strictNullChecks включено (также включите strict: true )

Тогда это будет string | number | undefined . В чем проблема?

Потому что это не может быть undefined , если ваше значение по умолчанию не равно undefined . Я хочу исключить этот тип undefined , чтобы пользователям не приходилось выполнять ненужную проверку на нуль для подавления ошибки undefined .

Если вы добавите | undefined к типу, конечно, он может быть неопределенным, и вы должны убедиться, что он не является неопределенным, когда пытаетесь вызвать метод.

<!-- Component.svelte -->
<script lang="ts">
  export let test: string | undefined = '' as any; // `string | undefined` means it can be undefined.

  test.toUpperCase(); // not safe - because `test` can be `undefined`

  test?.toUpperCase(); // safe
</script>

<!-- Other component -->
<script>
  import Component from './Component.svelte';
</script>

<Componen test={undefined} />

Единственная проблема, которую я вижу в настоящее время, заключается в том, что расширение svelte должно сделать опору необязательной, если она имеет начальное значение.

Вместо того, чтобы проверять undefined в типе здесь , я думаю, мы можем использовать VariableDeclaration.initializer здесь

потому что компилятор svelte компилирует его в

let { test = '' } = $$props

поэтому test не может быть undefined , даже если вы явно передаете undefined в качестве реквизита. Он может быть неопределенным только в том случае, если вы переназначите его на undefined позже.

Может быть, было бы слишком сложно или невозможно сделать то, что я намереваюсь сделать. И это может быть просто пограничный случай, который мало кто будет использовать.

Он по-прежнему может быть неопределенным, если вы передаете переменную, которая изменяется на неопределенную.
https://svelte.dev/repl/hello-world?version=3.23.2

Тогда это реактивный оператор, который, возможно, undefined ? Возможно, нам следует просто сделать реактивным и потребовать от пользователя явного приведения типа значения по умолчанию.

export let a: string | number | undefined = '' as string | number

Кастинг может сработать. но в js у него не будет неопределенного типа в функции

    /**<strong i="8">@type</strong> { string | number | undefined }*/
    let name = /**<strong i="9">@type</strong> {string | number} */ ("world"),
        world = '';

    name

    function a() {
        name
    }

пример игровой площадки js

Вместо того, чтобы проверять тип undefined здесь, я думаю, мы можем использовать здесь VariableDeclaration.initializer.

хорошая точка зрения! Он может различать необязательные реквизиты и, возможно, неопределенные

Вот что я имею в виду с дополнительными реквизитами: https://github.com/PatrickG/language-tools/commit/c5f00f75df74c8e3dcfc9842dad4256b9d4f29f2

А с as any после инициализатора vscode больше не считает export let test: string | number = ''; строкой. https://github.com/PatrickG/language-tools/commit/7f630bbf7d66a037590384d3e2a7f8b7314b622c

Могу ли я создать PR с моими изменениями?

Я думаю, что с первым все в порядке!
Еще один минус as any заключается в том, что он не будет проверять тип. Так что, возможно, его нужно привести к тому, что определил пользователь.

let a: string | number = true as any;

Также кастинг нужно делать через jsdoc в js. Я попробовал это сегодня.
Что касается неопределенной проблемы, я отказываюсь от нее. Поскольку мы не можем найти общую функцию, которая может помочь. Мы могли только вручную проверить, не определен ли его инициализатор, но не не определена ли переменная, переданная в качестве инициализатора. Ложноотрицательные результаты кажутся более важными.

Я думаю, что с первым все в порядке!
Еще один минус as any заключается в том, что он не будет проверять тип. Так что, возможно, его нужно привести к тому, что определил пользователь.

let a: string | number = true as any;

О верно.
Что насчет этого:

declare function __sveltets_initialize<T>(value: T): any;
let test: string | number = __sveltets_initialize<string | number>('');
test; // string | number

let test: string | number = __sveltets_initialize<string | number>(true); // error because `true` is not `string` or `number`

Также кастинг нужно делать через jsdoc в js. Я попробовал это сегодня.

Я еще не изучал материал jsdoc

обновление: есть еще один способ сделать as any

export let a: number | string = '1',
  b = a;

к

declare function __sveltets_any(dummy: any): any;

let a: number | string = '1'
a = __sveltets_any(a);
let b = a;

Утверждение типа не требуется, и инициализатор получил проверку типа. Так что это будет показывать ошибку ввода:

export let a: ISomeInterface = {};
export let b: string | number = true;

Я тоже думал о переназначении, но хотел предотвратить его, потому что я думаю, что это сложнее сделать ^^
Вы реализуете это?

да. Я реализовал здесь переназначение, но все еще нуждаюсь в некоторых работах по очистке и тестированию.
Другой фокусируется на переменной $:

@jasonlyu123 jasonlyu123 все, о чем была проблема, исправлено вашим пиарщиком? (спрашивая, могу ли я закрыть это)

Да. Спасибо

Была ли эта страница полезной?
0 / 5 - 0 рейтинги