nie można ponownie zadeklarować zmiennej o zakresie blokowym (maszynopis)

106

Buduję aplikację węzła, a wewnątrz każdego pliku w .js używam do tego wymagania w różnych pakietach.

let co = require("co");

Ale dostaję

wprowadź opis obrazu tutaj

itd. Więc używając maszynopisu wydaje się, że może istnieć tylko jedna taka deklaracja / wymaganie w całym projekcie? Jestem zdezorientowany, ponieważ myślałem, że letzakres dotyczy bieżącego pliku.

Właśnie miałem projekt, który działał, ale po refaktorze teraz pojawiają się te błędy w każdym miejscu.

Czy ktoś może wyjaśnić?

dcsan
źródło
1
Co powiesz na to - niech co_module = require ("co"); Napotkałem coś podobnego i to rozwiązało błąd.
tyrion
1
Wygląda na to, że jest to błąd maszynopisu. Zrobiłem tutaj minimalny przykład: gist.github.com/rjmunro/428ec644b6e53a499ca3a5ba8de2edc7
rjmunro
5
2,5 roku później i wracam do własnego pytania, to nadal jest problem. tym razem z wbudowanymi węzłami. const fs = require('fs')daje podobny błąd, więc nie jestem pewien, z której biblioteki to zaimportować ...
dcsan
Fakt, że TS nadal to robi, jest śmieszny
GN.

Odpowiedzi:

68

Jeśli chodzi o sam błąd, letsłuży do deklarowania zmiennych lokalnych , które istnieją w zakresach bloków, a nie w zakresach funkcji. Jest też bardziej rygorystyczny niż var, więc nie możesz robić takich rzeczy:

if (condition) {
    let a = 1;
    ...
    let a = 2;
}

Zauważ również, że caseklauzule wewnątrz switchbloków nie tworzą własnych zakresów bloków, więc nie możesz ponownie zadeklarować tej samej zmiennej lokalnej w wielu cases bez użycia {}do utworzenia każdego bloku.


Jeśli chodzi o import, prawdopodobnie otrzymujesz ten błąd, ponieważ TypeScript nie rozpoznaje twoich plików jako rzeczywistych modułów i pozornie definicje na poziomie modelu stają się dla niego definicjami globalnymi.

Spróbuj zaimportować moduł zewnętrzny w standardowy sposób ES6 , który nie zawiera wyraźnego przypisania i powinien sprawić, że TypeScript poprawnie rozpozna twoje pliki jako moduły:

import * as co from "./co"

Będzie to nadal skutkować błędem kompilacji, jeśli masz już coś nazwanego co, zgodnie z oczekiwaniami. Na przykład będzie to błąd:

import * as co from "./co"; // Error: import definition conflicts with local definition
let co = 1;

Jeśli pojawia się błąd „nie można znaleźć modułu co” ...

TypeScript uruchamia pełne sprawdzanie typu względem modułów, więc jeśli nie masz definicji TS dla modułu, który próbujesz zaimportować (np. Ponieważ jest to moduł JS bez plików definicji), możesz zadeklarować swój moduł w .d.tspliku definicji, który nie nie zawierają eksportu na poziomie modułu:

declare module "co" {
    declare var co: any;
    export = co;
}
John Weisz
źródło
9
daje to „nie można znaleźć modułu co”. Próbowałem też, typings install coco daje Unable to find "co" in the registry. jakieś inne pomysły?
dcsan
Mam ten sam problem, co @dcsan, który mówi, że nie może znaleźć modułu, mimo że wyraźnie mam go zainstalowanego npm.
justin.m.chase
Może to być spowodowane ścieżką względną. Nie jestem zaznajomiony z zarządzaniem modułami NodeJS, ale w RequireJS, jeśli odwołania do modułów są względne, bieżący folder musi być wyraźnie oznaczony. Oznacza to, że ./cozamiast tego co, jeśli co.ts znajduje się w tym samym folderze (lub skompilowanym wyjściu, co.js).
John Weisz
1
uważaj, „* as xxx” jest ważne. A więc nie „importuj xxx z ...”, ale „importuj * jako xxx z ...”
Nurbol Alpysbayev
29

Najlepsze wyjaśnienie, jakie mogłem uzyskać, pochodzi z postu Tamasa Piro .

TLDR; TypeScript używa typów DOM dla globalnego środowiska wykonawczego. W twoim przypadku globalny obiekt okna ma właściwość „co”.

Aby rozwiązać ten problem:

  1. Zmień nazwę zmiennej lub
  2. Użyj modułów TypeScript i dodaj pusty eksport {}:
export {};

lub

  1. Skonfiguruj opcje kompilatora, nie dodając typów DOM:

Edytuj plik tsconfig.json w katalogu projektu TypeScript.

{
    "compilerOptions": {
        "lib": ["es6"]
      }
}
Neville Omangi
źródło
to jest dla klienta? mój pierwotny problem dotyczył kodu po stronie serwera i nie wierzę, że były używane opcje kompilatora DOM (stary projekt)
dcsan,
2
Potwierdzam, że dodanie export {}rozwiązało problem, jednak dodawanie "compilerOptions": { "lib": ["es6"] }NIE wydaje się pomagać ani podczas kompilacji, ani w VSCode.
rodzina adamsfamily
1
Link do oryginalnego posta jest martwy.
Cyclonecode
13

Otrzymałem ten podobny błąd podczas kompilowania mojej aplikacji Node.JS Typescript:

node_modules/@types/node/index.d.ts:83:15 - error TS2451: Cannot redeclare block-scoped variable 'custom'.

Poprawka polegała na usunięciu tego:

"files": [
  "./node_modules/@types/node/index.d.ts"
]

i zastąpić to tym:

"compilerOptions": {
  "types": ["node"]
}
Tom Mettam
źródło
10

Użyj IIFE(Immediately Invoked Function Expression), IIFE

(function () {
    all your code is here...

 })();
Pasować
źródło
Prosty. Działa świetnie. Dziękuję Ci! (W moim przypadku deklarowałem const expect = chai.expect;użycie testów Cucumber w projekcie Angular 5).
Maxime Lafarie
7

Dla tych, którzy przyjeżdżają tutaj w tym wieku, oto proste rozwiązanie tego problemu. Przynajmniej zadziałało dla mnie na zapleczu. Nie sprawdziłem kodu frontendu.

Poprostu dodaj:

export {};

u góry twojego kodu.

Podziękowania dla EUGENE MURAVITSKY

Obinna Nnenanya
źródło
1

Mam ten sam problem, a moje rozwiązanie wygląda tak:

// *./module1/module1.ts*
export module Module1 {
    export class Module1{
        greating(){ return 'hey from Module1'}
    }
}


// *./module2/module2.ts*
import {Module1} from './../module1/module1';

export module Module2{
    export class Module2{
        greating(){
            let m1 = new Module1.Module1()
            return 'hey from Module2 + and from loaded Model1: '+ m1.greating();
        }
    }
}

Teraz możemy go używać po stronie serwera:

// *./server.ts*
/// <reference path="./typings/node/node.d.ts"/>
import {Module2} from './module2/module2';

export module Server {
    export class Server{
        greating(){
            let m2 = new Module2.Module2();
            return "hello from server & loaded modules: " + m2.greating();
        }
    }
}

exports.Server = Server;

// ./app.js
var Server = require('./server').Server.Server;
var server = new Server();
console.log(server.greating());

A także po stronie klienta:

// *./public/javscripts/index/index.ts*

import {Module2} from './../../../module2/module2';

document.body.onload = function(){
    let m2 = new Module2.Module2();
    alert(m2.greating());
}

// ./views/index.jade
extends layout

block content
  h1= title
  p Welcome to #{title}
  script(src='main.js')
  //
    the main.js-file created by gulp-task 'browserify' below in the gulpfile.js

I oczywiście plik łykowy do tego wszystkiego:

// *./gulpfile.js*
var gulp = require('gulp'),
    ts = require('gulp-typescript'),
    runSequence = require('run-sequence'),
    browserify = require('gulp-browserify'),
    rename = require('gulp-rename');

gulp.task('default', function(callback) {

    gulp.task('ts1', function() {
        return gulp.src(['./module1/module1.ts'])
            .pipe(ts())
            .pipe(gulp.dest('./module1'))
    });

    gulp.task('ts2', function() {
        return gulp.src(['./module2/module2.ts'])
            .pipe(ts())
            .pipe(gulp.dest('./module2'))
    });

    gulp.task('ts3', function() {
        return gulp.src(['./public/javascripts/index/index.ts'])
            .pipe(ts())
            .pipe(gulp.dest('./public/javascripts/index'))
    });

    gulp.task('browserify', function() {
        return gulp.src('./public/javascripts/index/index.js', { read: false })
            .pipe(browserify({
                insertGlobals: true
            }))
            .pipe(rename('main.js'))
            .pipe(gulp.dest('./public/javascripts/'))
    });

    runSequence('ts1', 'ts2', 'ts3', 'browserify', callback);
})

Zaktualizowano. Oczywiście nie jest konieczne oddzielne kompilowanie plików maszynopisu. runSequence(['ts1', 'ts2', 'ts3'], 'browserify', callback)działa idealnie.

django dev
źródło
7
Na wypadek, gdyby ktoś zniechęcił się do języka TypeScript gadatliwością i powtarzalnością tego pliku, nikt tego nie robi.
Daniel Earwicker
0

Otrzymałem ten błąd podczas aktualizacji

gulp-maszynopis 3.0.2 → 3.1.0

Przywrócenie wersji 3.0.2 naprawiło to

danday74
źródło
0

W moim przypadku tsconfig.jsonrozwiązany problem:

{
  "compilerOptions": {
    "esModuleInterop": true,
    "target": "ES2020",
    "moduleResolution": "node"
  }
}

Nie powinno być type: modulew package.json.

Daniel
źródło