Может утверждать, что переменная является экземпляром String в Deno

Кажется, я не могу утверждать экземпляры string в Deno:

import {
  assertInstanceOf
} from "https://deno.land/[email protected]/testing/asserts.ts";

assertInstanceOf( "foo", string );

Броски:

error: TS2693 [ERROR]: 'string' only refers to a type, but is being used as a value here.
assertInstanceOf( "foo", string );
                         ~~~~~~
    at file:///home/jmerelo/Code/my-stackoverflow-examples/js/string-assert.ts:6:26

Достаточно справедливо, давайте попробуем это

assertInstanceOf( "foo", String );

Теперь я в замешательстве:

Uncaught error from ./string-assert.ts FAILED

 ERRORS 

./string-assert.ts (uncaught error)
error: AssertionError: Expected object to be an instance of "String" but was "string".

Любая идея о том, что было бы правильным типом здесь?

Здесь явно есть обходной путь, чтобы использовать typeof. Но я хотел бы знать, как решить эту Уловку-22.

Разве это не должна быть "string" строка с содержимым «строка»? Идентификатор string, набранный строчными буквами, не должен ни на что ссылаться во время выполнения. Если в настройках нет чего-то, что делает внешний контекст доступным во время выполнения? String в верхнем регистре будет относиться к строковому конструктору. И примитивные строки не являются его экземплярами: "hello" instanceof String есть false.

VLAZ 31.01.2023 15:29

Проверка документации не говорит, что вы можете утверждать примитивы. В нем очень явно указано: «Чтобы проверить, является ли объект экземпляром определенного конструктора», который, опять же, примитивы не являются экземплярами конструктора. Явно не выполняет проверку уровня типа TS во время выполнения.

VLAZ 31.01.2023 15:31

@VLAZ, я думаю, это обходной путь, верно?

jjmerelo 31.01.2023 17:17

В документации также показано, что вы можете создавать свои собственные утверждения. Так что вы, вероятно, можете просто сделать один для примитивных типов.

VLAZ 31.01.2023 17:17
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой 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
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Здесь явно есть обходной путь, чтобы использовать typeof. Но я хотел бы знать, как решить эту Уловку-22.

Это не Уловка-22 , а ложная предпосылка . В JavaScript: хотя примитивы в некоторых аспектах выглядят как объекты , они не являются объектами (см. типы данных и структуры данных JavaScript ) — поэтому они не являются полезными операндами для использования с instanceof , потому что оценка всегда будет false (см. спецификацию):

instanceof

Оператор instanceof проверяет, появляется ли свойство прототипа конструктора где-либо в цепочке прототипов объекта.

Для строк это объясняется далее в статье MDN String в разделе Строковые примитивы и объекты String.

Ниже приведен пример кода, демонстрирующий, как различать и утверждать, является ли значение строковым литералом или экземпляром объекта String , используя стандартную библиотеку тестирования Deno и определяемые пользователем функции защиты типа.

Игровая площадка ТС

module.ts:

import { assert } from "https://deno.land/[email protected]/testing/asserts.ts";

function isStringLiteral(actual: unknown): actual is string {
  return typeof actual === "string";
}

function isStringInstance(actual: unknown): actual is String {
  return typeof actual === "object" && actual instanceof String;
}

function isAnyString(actual: unknown): actual is string | String {
  return isStringLiteral(actual) || isStringInstance(actual);
}

const testCases: [name: string, value: unknown][] = [
  ["string literal", "foo"],
  ["string instance", new String("foo")],
  ["number literal", 42],
  ["number instance", new Number(42)],
];

console.info("Testing for string types...");

for (const [name, value] of testCases) {
  try {
    assert(isAnyString(value));
    console.info("✅", name);
  } catch {
    console.error("❌", name);
    continue;
  }

  try {
    assert(isStringLiteral(value));
    console.info("type:", "literal");
  } catch {
    assert(isStringInstance(value));
    console.info("type:", "instance");
  }
}

Выход:

% deno --version
deno 1.30.0 (release, x86_64-apple-darwin)
v8 10.9.194.5
typescript 4.9.4

% deno check module.ts

% echo $?
0

% deno run module.ts
Testing for string types...
✅ string literal
type: literal
✅ string instance
type: instance
❌ number literal
❌ number instance

Скомпилированный JavaScript со встроенным импортом:

// import { assert } from "https://deno.land/[email protected]/testing/asserts.ts";

// ---> Begin inlined imports

// https://deno.land/[email protected]/testing/asserts.ts?source#L19
class AssertionError extends Error {
  name = "AssertionError";
  constructor(message) {
    super(message);
  }
}

// https://deno.land/[email protected]/testing/asserts.ts?source#L138
/** Make an assertion, error will be thrown if `expr` does not have truthy value. */
function assert(expr, msg = "") {
  if (!expr) {
    throw new AssertionError(msg);
  }
}

// <--- End inlined imports

function isStringLiteral(actual) {
  return typeof actual === "string";
}
function isStringInstance(actual) {
  return typeof actual === "object" && actual instanceof String;
}
function isAnyString(actual) {
  return isStringLiteral(actual) || isStringInstance(actual);
}
const testCases = [["string literal", "foo"], ["string instance", new String("foo")], ["number literal", 42], ["number instance", new Number(42)]];
console.info("Testing for string types...");
for (const [name, value] of testCases) {
  try {
    assert(isAnyString(value));
    console.info("✅", name);
  } catch {
    console.error("❌", name);
    continue;
  }
  try {
    assert(isStringLiteral(value));
    console.info("type:", "literal");
  } catch {
    assert(isStringInstance(value));
    console.info("type:", "instance");
  }
}

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