e :: t doesn’t mean “convert expression e to type t”, it’s just an annotation that says “e has type t (already)”. So this:
let y = x :: Int in y
Means: assert that x has type Int, set y equal to x, and return y. That’s why you got a type mismatch: x does not have type Int as you are claiming to the compiler. And this:
let x = x :: Integer
in if x >= 0 then x :: NT1 else x :: NT1
Means: declare a new variable x, set it equal to itself (an infinite loop), asserting that it has type Integer, then test whether that infinite loop returns a nonnegative value; either way, return x, asserting that it has type NT1 (this contradicts the Integer from before).
To convert between Integer and Int, you can use fromIntegral :: (Integral a, Num b) => a -> b, which converts any integral type (such as Int or Integer) into any numeric type (such as Int, Integer, Float, Double, or Ratio).
For converting from newtypes, you can use pattern-matching:
fromNT1ToInt :: NT1 -> Int
fromNT1ToInt (NT1 x) = fromIntegral x
Or add a record accessor function to the newtype and use that:
newtype NT1 = NT1 { nt1Val :: Integer }
-- Note: nt1Val :: NT1 -> Integer
fromNT1ToInt :: NT1 -> Int
fromNT1ToInt nt = fromIntegral (nt1Val nt)
-- Or, with function composition (.):
fromNT1ToInt = fromIntegral . nt1Val
Or, finally, use coerce from Data.Coerce:
import Data.Coerce (coerce)
fromNT1ToInt :: NT1 -> Int
fromNT1ToInt nt = fromIntegral (coerce nt :: Integer)
And of course, to construct a newtype you just use its constructor—in this case, NT1 :: Integer -> NT1, e.g. NT1 5.