10 minutos
Guia de Migração do AssemblyScript
Up until now, Subgraphs have been using one of the first versions of AssemblyScript (v0.6). Finally we’ve added support for the newest one available (v0.19.10)! 🎉
That will enable Subgraph developers to use newer features of the AS language and standard library.
This guide is applicable for anyone using graph-cli/graph-ts below version 0.22.0. If you’re already at a higher than (or equal) version to that, you’ve already been using version 0.19.10 of AssemblyScript 🙂
Note: As of 0.24.0, graph-node can support both versions, depending on the apiVersion specified in the Subgraph manifest.
Recursos
Novas funcionalidades
TypedArrays can now be built fromArrayBuffers by using the newwrapstatic method (v0.8.1)- New standard library functions: 
String#toUpperCase,String#toLowerCase,String#localeCompareandTypedArray#set(v0.9.0) - Added support for x instanceof GenericClass (v0.9.2)
 - Added 
StaticArray<T>, a more efficient array variant (v0.9.3) - Added 
Array<T>#flat(v0.10.0) - Implemented 
radixargument onNumber#toString(v0.10.1) - Added support for separators in floating point literals (v0.13.7)
 - Added support for first class functions (v0.14.0)
 - Add builtins: 
i32/i64/f32/f64.add/sub/mul(v0.14.13) - Implement 
Array/TypedArray/String#at(v0.18.2) - Added support for template literal strings (v0.18.17)
 - Add 
encodeURI(Component)anddecodeURI(Component)(v0.18.27) - Add 
toString,toDateStringandtoTimeStringtoDate(v0.18.29) - Add 
toUTCStringforDate(v0.18.30) - Add 
nonnull/NonNullablebuiltin type (v0.19.2) 
Otimizações
Mathfunctions such asexp,exp2,log,log2andpowhave been replaced by faster variants (v0.9.0)- Slightly optimize 
Math.mod(v0.17.1) - Cache more field accesses in std Map and Set (v0.17.8)
 - Optimize for powers of two in 
ipow32/64(v0.18.2) 
Outros
- The type of an array literal can now be inferred from its contents (v0.9.0)
 - Updated stdlib to Unicode 13.0.0 (v0.10.0)
 
Como atualizar?
- Change your mappings 
apiVersioninsubgraph.yamlto0.0.9: 
1...2dataSources:3  ...4    mapping:5      ...6      apiVersion: 0.0.97      ...- Update the 
graph-cliyou’re using to thelatestversion by running: 
1# caso o tenha instalado globalmente2npm install --global @graphprotocol/graph-cli@latest34# ou no seu subgraph se o tiver como dependência de desenvolvimento5npm install --save-dev @graphprotocol/graph-cli@latest- Do the same for 
graph-ts, but instead of installing globally, save it in your main dependencies: 
1npm install --save @graphprotocol/graph-ts@latest- Siga o resto do guia para consertar as mudanças frágeis na linguagem.
 - Run 
codegenanddeployagain. 
Breaking changes (mudanças frágeis)
Anulabilidade
Na versão mais antiga do AssemblyScript, podias criar códigos assim:
1function load(): Value | null { ... }23let maybeValue = load();4maybeValue.aMethod();Mas na versão mais nova, como o valor é anulável, ele exige que confira, assim:
1let maybeValue = load()23if (maybeValue) {4  maybeValue.aMethod() // `maybeValue` is not null anymore5}…ou o force deste jeito:
1let maybeValue = load()! // breaks in runtime if value is null23maybeValue.aMethod()If you are unsure which to choose, we recommend always using the safe version. If the value doesn’t exist you might want to just do an early if statement with a return in you Subgraph handler.
Sombreamento Varíavel
Before you could do variable shadowing and code like this would work:
1let a = 102let b = 203let a = a + bPorém, isto não é mais possível, e o compilador retorna este erro:
1ERROR TS2451: Cannot redeclare block-scoped variable 'a'23 let a = a + b;4 ~~~~~~~~~~~~~5in assembly/index.ts(4,3)Renomeie as suas variáveis duplicadas, se tinha o sombreamento variável.
Comparações de Nulos
By doing the upgrade on your Subgraph, sometimes you might get errors like these:
1ERROR TS2322: Type '~lib/@graphprotocol/graph-ts/common/numbers/BigInt | null' is not assignable to type '~lib/@graphprotocol/graph-ts/common/numbers/BigInt'.2     if (decimals == null) {3                     ~~~~4 in src/mappings/file.ts(41,21)To solve you can simply change the if statement to something like this:
1if (!decimals) {23  // or45  if (decimals === null) {O mesmo acontece se fizer o != em vez de ==.
Casting (Conversão de tipos)
The common way to do casting before was to just use the as keyword, like this:
1let byteArray = new ByteArray(10)2let uint8Array = byteArray as Uint8Array // equivalent to: <Uint8Array>byteArrayPorém, isto só funciona em dois casos:
- Primitive casting (between types such as 
u8,i32,bool; eg:let b: isize = 10; b as usize); - Upcasting em herança de classe (subclass → superclass)
 
Exemplos:
1// primitive casting2let a: usize = 103let b: isize = 54let c: usize = a + (b as usize)1// upcasting on class inheritance2class Bytes extends Uint8Array {}34let bytes = new Bytes(2)5// <Uint8Array>bytes // same as: bytes as Uint8ArrayThere are two scenarios where you may want to cast, but using as/<T>var isn’t safe:
- Downcasting em herança de classe (superclass → subclass)
 - Entre dois tipos que compartilham uma superclasse
 
1// downcasting on class inheritance2class Bytes extends Uint8Array {}34let uint8Array = new Uint8Array(2)5// <Bytes>uint8Array // breaks in runtime :(1// between two types that share a superclass2class Bytes extends Uint8Array {}3class ByteArray extends Uint8Array {}45let bytes = new Bytes(2)6// <ByteArray>bytes // breaks in runtime :(For those cases, you can use the changetype<T> function:
1// downcasting on class inheritance2class Bytes extends Uint8Array {}34let uint8Array = new Uint8Array(2)5changetype<Bytes>(uint8Array) // works :)1// between two types that share a superclass2class Bytes extends Uint8Array {}3class ByteArray extends Uint8Array {}45let bytes = new Bytes(2)6changetype<ByteArray>(bytes) // works :)If you just want to remove nullability, you can keep using the as operator (or <T>variable), but make sure you know that value can’t be null, otherwise it will break.
1// remove anulabilidade2let previousBalance = AccountBalance.load(balanceId) // AccountBalance | null34if (previousBalance != null) {5  return previousBalance as AccountBalance // safe remove null6}78let newBalance = new AccountBalance(balanceId)For the nullability case we recommend taking a look at the nullability check feature, it will make your code cleaner 🙂
Também adicionamos alguns métodos estáticos em alguns tipos para facilitar o casting, sendo:
- Bytes.fromByteArray
 - Bytes.fromUint8Array
 - BigInt.fromByteArray
 - ByteArray.fromBigInt
 
Checagem de anulabilidade com acesso à propriedade
To use the nullability check feature you can use either if statements or the ternary operator (? and :) like this:
1let something: string | null = 'data'23let somethingOrElse = something ? something : 'else'45// ou67let somethingOrElse89if (something) {10  somethingOrElse = something11} else {12  somethingOrElse = 'else'13}However that only works when you’re doing the if / ternary on a variable, not on a property access, like this:
1class Container {2  data: string | null3}45let container = new Container()6container.data = 'data'78let somethingOrElse: string = container.data ? container.data : 'else' // doesn't compileO que retorna este erro:
1ERROR TS2322: Type '~lib/string/String | null' is not assignable to type '~lib/string/String'.23   let somethingOrElse: string = container.data ? container.data : "else";4                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Para consertar este problema, vale criar uma variável para aquele acesso à propriedade, para que o compilador faça a magia da checagem de anulabilidade:
1class Container {2  data: string | null3}45let container = new Container()6container.data = 'data'78let data = container.data910let somethingOrElse: string = data ? data : 'else' // compiles just fine :)Sobrecarga de operador com acesso à propriedade
Se tentar somar (por exemplo) um tipo anulável (de um acesso de propriedade) com um não-anulável, em vez de soltar um aviso de erro de tempo de compilação a dizer que um dos valores é anulável, o compilador AssemblyScript só compilará em silêncio, o que abre chances para o código quebrar em meio ao tempo de execução.
1class BigInt extends Uint8Array {2  @operator('+')3  plus(other: BigInt): BigInt {4    // ...5  }6}78class Wrapper {9  public constructor(public n: BigInt | null) {}10}1112let x = BigInt.fromI32(2)13let y: BigInt | null = null1415x + y // dá o erro de tempo de complação sobre anulabilidade1617let wrapper = new Wrapper(y)1819wrapper.n = wrapper.n + x // não dá erros de tempo de compilação como deveriaWe’ve opened a issue on the AssemblyScript compiler for this, but for now if you do these kind of operations in your Subgraph mappings, you should change them to do a null check before it.
1let wrapper = new Wrapper(y)23if (!wrapper.n) {4  wrapper.n = BigInt.fromI32(0)5}67wrapper.n = wrapper.n + x // agora o `n` é garantido a ser um BigIntInicialização de valor
Se tiver algum código como este:
1var value: Type // null2value.x = 103value.y = 'content'It will compile but break at runtime, that happens because the value hasn’t been initialized, so make sure your Subgraph has initialized their values, like this:
1var value = new Type() // initialized2value.x = 103value.y = 'content'E também se tiver propriedades anuláveis numa entidade GraphQL, como assim:
1type Total @entity {2  id: Bytes!3  amount: BigInt4}E tiver código parecido com este:
1let total = Total.load('latest')23if (total === null) {4  total = new Total('latest')5}67total.amount = total.amount + BigInt.fromI32(1)You’ll need to make sure to initialize the total.amount value, because if you try to access like in the last line for the sum, it will crash. So you either initialize it first:
1let total = Total.load('latest')23if (total === null) {4  total = new Total('latest')5  total.amount = BigInt.fromI32(0)6}78total.tokens = total.tokens + BigInt.fromI32(1)Or you can just change your GraphQL schema to not use a nullable type for this property, then we’ll initialize it as zero on the codegen step 😉
1type Total @entity {2  id: Bytes!3  amount: BigInt!4}1let total = Total.load('latest')23if (total === null) {4  total = new Total('latest') // já inicializa propriedades não-anuláveis5}67total.amount = total.amount + BigInt.fromI32(1)Iniciação de propriedade de classe
Se exportar quaisquer classes com propriedades que sejam outras classes (declaradas por você ou pela biblioteca padrão) como esta:
1class Thing {}23export class Something {4  value: Thing5}The compiler will error because you either need to add an initializer for the properties that are classes, or add the ! operator:
1export class Something {2  constructor(public value: Thing) {}3}45// ou67export class Something {8  value: Thing910  constructor(value: Thing) {11    this.value = value12  }13}1415// ou1617export class Something {18  value!: Thing19}Iniciação de arranjo
The Array class still accepts a number to initialize the length of the list, however you should take care because operations like .push will actually increase the size instead of adding to the beginning, for example:
1let arr = new Array<string>(5) // ["", "", "", "", ""]23arr.push('something') // ["", "", "", "", "", "something"] // size 6 :(Dependendo dos tipos que usa, por ex., anuláveis, e como os acessa, pode encontrar um erro de tempo de execução como este:
1ERRO Handler skipped due to execution failure, error: Mapping aborted at ~lib/array.ts, line 110, column 40, with message: Element type must be nullable if array is holey  wasm backtrace:     0: 0x19c4 - <unknown>!~lib/@graphprotocol/graph-ts/index/format         1: 0x1e75 - <unknown>!~lib/@graphprotocol/graph-ts/common/collections/Entity#constructor        2: 0x30b9 - <unknown>!node_modules/@graphprotocol/graph-ts/global/global/id_of_typeTo actually push at the beginning you should either, initialize the Array with size zero, like this:
1let arr = new Array<string>(0) // []23arr.push('something') // ["something"]Ou pode mudá-lo através do index:
1let arr = new Array<string>(5) // ["", "", "", "", ""]23arr[0] = 'something' // ["something", "", "", "", ""]Schema GraphQL
This is not a direct AssemblyScript change, but you may have to update your schema.graphql file.
Agora não há mais como definir campos nos seus tipos que são Listas Não Anuláveis. Se tiver um schema como este:
1type Something @entity {2  id: Bytes!3}45type MyEntity @entity {6  id: Bytes!7  invalidField: [Something]! # no longer valid8}You’ll have to add an ! to the member of the List type, like this:
1type Something @entity {2  id: Bytes!3}45type MyEntity @entity {6  id: Bytes!7  invalidField: [Something!]! # valid8}This changed because of nullability differences between AssemblyScript versions, and it’s related to the src/generated/schema.ts file (default path, you might have changed this).
Outros
- Aligned 
Map#setandSet#addwith the spec, returningthis(v0.9.2) - Arrays no longer inherit from ArrayBufferView, but are now distinct (v0.10.0)
 - Classes initialized from object literals can no longer define a constructor (v0.10.0)
 - The result of a 
**binary operation is now the common denominator integer if both operands are integers. Previously, the result was a float as if callingMath/f.pow(v0.11.0) - Coerce 
NaNtofalsewhen casting tobool(v0.14.9) - When shifting a small integer value of type 
i8/u8ori16/u16, only the 3 respectively 4 least significant bits of the RHS value affect the result, analogous to the result of ani32.shlonly being affected by the 5 least significant bits of the RHS value. Example:someI8 << 8previously produced the value0, but now producessomeI8due to masking the RHS as8 & 7 = 0(3 bits) (v0.17.0) - Bug fix of relational string comparisons when sizes differ (v0.17.8)