Como você produz um arquivo de definição "typings" .d.ts a partir de uma biblioteca JavaScript existente?

192

Estou usando muitas bibliotecas, tanto minhas quanto de terceiros. Vejo que o diretório "typings" contém um pouco do Jquery e WinRT ... mas como eles são criados?

Hotrodmonkey
fonte

Respostas:

232

Existem algumas opções disponíveis, dependendo da biblioteca em questão, de como está escrita e de qual nível de precisão você está procurando. Vamos revisar as opções, em ordem decrescente de conveniência.

Talvez já exista

Sempre verifique DefinitelyTyped ( https://github.com/DefinitelyTyped/DefinitelyTyped ) primeiro. Este é um repositório da comunidade cheio de literalmente milhares de arquivos .d.ts e é muito provável que o que você está usando já esteja lá. Você também deve verificar o TypeSearch ( https://microsoft.github.io/TypeSearch/ ), que é um mecanismo de pesquisa para arquivos .d.ts publicados pelo NPM; isso terá um pouco mais de definições que DefinitelyTyped. Alguns módulos também estão enviando suas próprias definições como parte de sua distribuição NPM, para ver também se esse é o caso antes de tentar escrever suas próprias.

Talvez você não precise de um

O TypeScript agora suporta o --allowJssinalizador e fará mais inferências baseadas em JS nos arquivos .js. Você pode tentar incluir o arquivo .js em sua compilação, juntamente com a --allowJsconfiguração para verificar se isso fornece informações de tipo boas o suficiente. O TypeScript reconhecerá coisas como as classes no estilo ES5 e os comentários JSDoc nesses arquivos, mas poderá ser desativado se a biblioteca se inicializar de uma maneira estranha.

Comece com --allowJs

Se --allowJsvocê obteve resultados decentes e deseja escrever um arquivo de definição melhor, você pode combinar --allowJscom --declarationpara ver o "melhor palpite" do TypeScript nos tipos da biblioteca. Isso fornecerá um ponto de partida decente e poderá ser tão bom quanto um arquivo criado manualmente, se os comentários do JSDoc estiverem bem escritos e o compilador puder encontrá-los.

Primeiros passos com dts-gen

Se --allowJsnão funcionou, convém usar o dts-gen ( https://github.com/Microsoft/dts-gen ) para obter um ponto de partida. Essa ferramenta usa a forma de tempo de execução do objeto para enumerar com precisão todas as propriedades disponíveis. No lado positivo, isso tende a ser muito preciso, mas a ferramenta ainda não suporta a raspagem dos comentários do JSDoc para preencher outros tipos. Você executa assim:

npm install -g dts-gen
dts-gen -m <your-module>

Isso será gerado your-module.d.tsna pasta atual.

Aperte o botão Adiar

Se você quiser fazer tudo mais tarde e ficar sem tipos por um tempo, no TypeScript 2.0, agora você pode escrever

declare module "foo";

que lhe permitirá importo "foo"módulo com tipo any. Se você tem um global com o qual deseja lidar mais tarde, basta escrever

declare const foo: any;

o que lhe dará uma foovariável.

Ryan Cavanaugh
fonte
25
Ai ... isso vai ser uma barreira significativa para a entrada em muitos casos. Seria bom ter uma ferramenta que pudesse gerar pelo menos "melhores palpites" com base na inferência de tipo. Embora eles possam não ser ótimos, eles podem pelo menos ser ajustados com o tempo.
Hotrodmonkey
7
+1 - Mais boas notícias: --declarationsgera o .jsarquivo e o .d.tsarquivo, o que significa que você só precisa executar uma única compilação.
Fenton
67
Uma coleção de definições de alta qualidade para as bibliotecas populares podem ser encontradas em github.com/borisyankov/DefinitelyTyped
Boris Yankov
10
Uma ferramenta de 'melhor palpite' não será melhor do que o IntelliSense já existente no TypeScript. O benefício das definições de tipo está em fornecer mais informações ao compilador do que ele pode "adivinhar".
Boris Yankov
12
--allowJscom --declarationopções não pode ser combinada (testada no TypeScript 1.8 e 2.0). Se eu tentar, eu recebo: #error TS5053: Option 'allowJs' cannot be specified with option 'declaration'
275 Alexey
52

Você pode usar tsc --declaration fileName.tscomo Ryan descreve, ou pode especificar declaration: trueabaixo compilerOptions, tsconfig.jsonassumindo que você já teve um tsconfig.jsonsob seu projeto.

JayKan
fonte
4
Essa é a melhor resposta se você estiver desenvolvendo um (s) módulo (s) Angular 2 que gostaria de compartilhar.
Darcy
Se eu tentar tsc --declaration test.ts, recebo o erro Cannot find name...para os tipos para os quais estou tentando criar um arquivo de declaração :) Então, preciso dos tipos antes de poder declará-los?
Kokodoko
2
@Kokodoko, você pode tentar adicionar declaration: trueao seu tsconfig.jsonarquivo?
precisa saber é o seguinte
Obrigado, eu só queria gerar * .d.ts a partir de * .ts.
vintproykt
16

A melhor maneira de lidar com isso (se um arquivo de declaração não estiver disponível no DefinitelyTyped ) é escrever declarações apenas para as coisas que você usa e não para a biblioteca inteira. Isso reduz muito o trabalho - além disso, o compilador está lá para ajudar, reclamando sobre os métodos ausentes.

Gorgi Kosev
fonte
15

Como Ryan diz, o compilador tsc possui uma opção --declarationque gera um .d.tsarquivo a partir de um .tsarquivo. Observe também que (salvo erros), o TypeScript deve ser capaz de compilar Javascript, para que você possa passar o código javascript existente para o compilador tsc.

CCoder
fonte
1
parece estar passando arquivos * .js para o tsc gera um erro "Erro ao ler o arquivo" angular-resource.js ": Arquivo não encontrado". Portanto, você deve renomear explicitamente os arquivos * .js para * .ts para poder usar o tsc. Veja esta questão para mais detalhes - Eu tentei usar isso em AngularJS: typescript.codeplex.com/workitem/26
James Strachan
3
Pelo que sei, o tsc pode compilar qualquer JavaScript válido, mas se não for TypeScript válido (a compilação fornece avisos), o sinalizador --declarations não gera um arquivo .d.ts, portanto, a menos que sua biblioteca seja escrita em TypeScript, você ainda é necessário criar manualmente o arquivo de declarações.
agradl
3

Aqui está um PowerShell que cria um único arquivo de definição TypeScript, uma biblioteca que inclui vários *.jsarquivos com JavaScript moderno.

Primeiro, mude todas as extensões para .ts.

Get-ChildItem | foreach { Rename-Item $_ $_.Name.Replace(".js", ".ts") }

Segundo, use o compilador TypeScript para gerar arquivos de definição. Haverá muitos erros de compilador, mas podemos ignorá-los.

Get-ChildItem | foreach { tsc $_.Name  }

Por fim, combine todos os *.d.tsarquivos em um index.d.ts, removendo as importinstruções e removendo as defaultde cada instrução de exportação.

Remove-Item index.d.ts; 

Get-ChildItem -Path *.d.ts -Exclude "Index.d.ts" | `
  foreach { Get-Content $_ } | `
  where { !$_.ToString().StartsWith("import") } | `
  foreach { $_.Replace("export default", "export") } | `
  foreach { Add-Content index.d.ts $_ }

Isso termina com um único index.d.tsarquivo utilizável que inclui muitas das definições.

Shaun Luttin
fonte
2
Segunda etapa, Get-ChildItem | foreach { tsc - declaração $ _. Nome} funcionou (adicionado em falta - parâmetro de declaração)
Guru_07
3

Ao criar sua própria biblioteca, você pode criar *.d.tsarquivos usando o tsccomando (TypeScript Compiler) da seguinte maneira: (supondo que você esteja criando sua biblioteca na dist/libpasta)

tsc -d --declarationDir dist/lib --declarationMap --emitDeclarationOnly
  • -d( --declaration): gera os *.d.tsarquivos
  • --declarationDir dist/lib: Diretório de saída para arquivos de declaração gerados.
  • --declarationMap: Gera um mapa de origem para cada arquivo '.d.ts' correspondente.
  • --emitDeclarationOnly: Emita apenas arquivos de declaração '.d.ts'. (sem JS compilado)

(veja os documentos para todas as opções do compilador de linha de comando)

Ou, por exemplo, no seu package.json:

"scripts": {
    "build:types": "tsc -d --declarationDir dist/lib --declarationMap --emitDeclarationOnly",
}

e depois execute: yarn build:types(ou npm run build:types)

magikMaker
fonte
Ainda não consigo descobrir como gerar os d.tsarquivos e poder usar interfaces. Você tem algum exemplo?
Danosaure 14/01
O script npm acima irá gerar os *.d.tsarquivos e colocá-los na dist/libpasta Você precisa de um tsconfig.jsonarquivo na raiz do seu projeto, mas deve estar lá para que o projeto funcione de qualquer maneira.
magikMaker 14/01
Eu sou incapaz de usá-los, uma vez expostos. Tenho o seguinte post stackoverflow.com/questions/59742688 se você pode fazê-lo funcionar?
Danosaure 14/01
2

Eu procuraria um mapeamento existente de suas bibliotecas JS de terceiros que suportem Script # ou SharpKit. Os usuários desses compiladores cruzados de C # para .js terão enfrentado o problema que você enfrenta agora e podem ter publicado um programa de código aberto para varrer sua biblioteca de terceiros e converter em classes C # esqueléticas. Nesse caso, corte o programa do scanner para gerar o TypeScript no lugar de C #.

Caso contrário, traduzir uma interface pública C # para sua biblioteca de terceiros em definições TypeScript pode ser mais simples do que fazer o mesmo lendo o JavaScript de origem.

Meu interesse especial é a estrutura ExtJS RIA do Sencha e sei que existem projetos publicados para gerar uma interpretação em C # para Script # ou SharpKit

camelCase
fonte
FYI: Acabei de criar
André
hey Camel Case, eu coloquei um blog sobre o uso ExtJs com typescript: blorkfish.wordpress.com/2013/01/28/using-extjs-with-typescript
blorkfish